{"openapi":"3.1.1","info":{"title":"Lunedo API","version":"1","description":"The Lunedo API lets scripts and integrations read and change the data of this instance. Every route is versioned under `/api/v1`.\n\n## Create a token\n\nScripts authenticate with an API token. There are two kinds:\n\n- **Personal tokens** act as your own account. Create one while signed in, in your account settings under Security.\n- **Service account tokens** act as a service account of an organization, which keeps working when people leave. Holders of the \"integrations and API\" area create service accounts and their tokens.\n\nA token starts with `ld_` and is shown only once, when it is created. Choose its scopes from the permission areas, each with `view` or `manage`, and optionally limit it to one organization. At every request, the token can do only what both its scopes and its owner's current permissions allow. A token has no expiry unless you set a date when you create it. If the instance or an organization sets a maximum lifetime, every new token needs a date within it, and a token created without one gets the maximum. Creating and revoking tokens needs a signed-in session; a token cannot manage tokens.\n\n## Your first request\n\nSend the token in the `Authorization` header. Tokens in the query string are never accepted, and a request that carries both a session cookie and a token is rejected.\n\n```sh\ncurl -H \"Authorization: Bearer ld_...\" https://wiki.example.org/api/v1/organizations/{organizationId}\n```\n\nRequests with a token need no cross-site request header.\n\n## Pagination\n\nLists return one page at a time:\n\n```json\n{ \"items\": [], \"nextCursor\": \"eyJ...\" }\n```\n\nPass `nextCursor` as the `cursor` query parameter to get the next page, until `nextCursor` is `null`. `limit` sets the page size, from 1 to 200, default 50.\n\n## Errors\n\nErrors follow RFC 9457 Problem Details with the media type `application/problem+json`. Branch on `type`; it is stable, for example `urn:lunedo:problem:forbidden`. `code` repeats its last part. Invalid input lists the affected fields in `fields`.\n\n## Rate limits\n\nEach token may send a configurable number of requests per minute, 600 by default. Above that, the API answers `429` with the problem type `urn:lunedo:problem:rateLimited` and a `Retry-After` header with the seconds to wait.\n","license":{"name":"AGPL-3.0-only","identifier":"AGPL-3.0-only"}},"servers":[{"url":"/","description":"This instance"}],"tags":[{"name":"Access","description":""},{"name":"Access requests","description":""},{"name":"Announcements","description":""},{"name":"Attachments","description":""},{"name":"Audit log","description":"Reading and exporting the tamper-evident audit log."},{"name":"Backups","description":"Scheduled backups, their target and retention, test restores and backup warnings of the instance."},{"name":"Blog","description":""},{"name":"Chat channels","description":""},{"name":"Comments","description":""},{"name":"Diagrams","description":"Files and images of draw.io, Mermaid and PlantUML diagrams in pages."},{"name":"Embeds","description":"External services whose content pages can embed, from the allowlist of the instance and organization."},{"name":"Exports","description":""},{"name":"Groups","description":"Groups of accounts and their managers."},{"name":"Home","description":""},{"name":"Imports","description":"Imports of Confluence spaces, Markdown and Word into a new space in quarantine. Importing needs the organization area spaces at manage; API tokens need the organization scope spaces at manage."},{"name":"Instance","description":"Organizations, accounts, roles and settings of the whole instance."},{"name":"Knowledge base articles","description":""},{"name":"Knowledge base reviews","description":"Review intervals and reminders of knowledge base articles, the list of articles to review, marking them as reviewed, and the internal source pages they are based on."},{"name":"Knowledge base statistics","description":"What readers search and read in the portal of a knowledge base and how they rate its articles, without any reference to a person."},{"name":"Knowledge bases","description":"Who may read a knowledge base, its categories, contact addresses, article templates with required sections, and articles with their numbers and sections."},{"name":"Meetings","description":""},{"name":"Members","description":"Members, collaborators, guests and invitations of an organization."},{"name":"One-on-ones","description":""},{"name":"Operations","description":""},{"name":"Organizations","description":"Organizations, their domains and break-glass access."},{"name":"Ownership and status","description":""},{"name":"Page access","description":""},{"name":"Pages","description":"The page tree with pages, folders and links, page content, labels and backlinks."},{"name":"Reports","description":""},{"name":"Roles","description":"Custom roles and role assignments of an organization."},{"name":"Search","description":"Searching pages, blog posts and comments the caller can read."},{"name":"Service accounts","description":"Accounts for scripts and integrations, owned by an organization."},{"name":"Settings","description":"Settings of an organization."},{"name":"Share links","description":""},{"name":"Spaces","description":"Spaces, their settings and permissions, and personal spaces."},{"name":"Storage","description":"Usage of the file store, warning levels and operations contacts of the instance."},{"name":"Tasks","description":""},{"name":"Templates","description":"Page templates of the instance, organizations and spaces, the template gallery, the images templates hold, and export and import of templates as files."},{"name":"Trash","description":"Deleting and restoring content in two trash stages, archiving spaces and deleting spaces."},{"name":"Versions","description":"Drafts, publishing, editing modes, versions, comparison and restoring of pages."},{"name":"Watching","description":"Watching and muting pages, blog posts, meeting series and spaces."},{"name":"Whiteboards","description":""}],"paths":{"/api/v1/access-requests/{requestId}":{"get":{"operationId":"accessRequests.get","summary":"Get an access request","description":"Returns a request of the caller, or a request the caller may decide as a space admin or as someone who may share the page.\n\nRequires the permission `instance.content.view` on the instance. Needs a signed-in session; API tokens are refused.","tags":["Access requests"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"sessionCookie":[]}],"parameters":[{"name":"requestId","in":"path","required":true,"description":"ID of the access request.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The request.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the request."},"requester":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]},"email":{"description":"E-mail address, when the caller may see it.","type":["string","null"]}},"required":["id","name","email"],"additionalProperties":false,"description":"Who asks."},"target":{"type":"string","description":"Whether the request is for a whole space or for a page. New values can be added in later versions; handle unknown values.","x-extensible-enum":["space","page"]},"spaceId":{"anyOf":[{"type":"string","format":"uuid","description":"The space."},{"type":"null"}],"description":"The space, or null when the requester cannot see the page the request is for."},"spaceName":{"type":"string","description":"Name of the space; empty when the requester cannot see it."},"itemId":{"anyOf":[{"type":"string","format":"uuid","description":"The page."},{"type":"null"}],"description":"The page; null for the whole space and when the requester cannot see the page."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the page in the addresses of the app."},{"type":"null"}],"description":"Number of the page in the addresses of the app, when the caller may see its title; null for the whole space."},"itemTitle":{"description":"Title of the page, when the caller may see it.","type":["string","null"]},"message":{"type":"string","description":"Message of the requester."},"status":{"type":"string","description":"`satisfied` means the person got access another way. New values can be added in later versions; handle unknown values.","x-extensible-enum":["open","approved","declined","withdrawn","satisfied"]},"role":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"]},{"type":"null"}],"description":"The role given when approved."},"decidedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who decided; null when the requester cannot see the page."},"decidedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When it was decided. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When it was sent. ISO 8601 timestamp in UTC."}},"required":["id","requester","target","spaceId","spaceName","itemId","number","itemTitle","message","status","role","decidedBy","decidedAt","createdAt"],"additionalProperties":false,"description":"A request for access to a space or page."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","requester":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a22","name":"Mia Kranz","email":"mia.kranz@example.org"},"target":"space","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a00","spaceName":"IT Operations","itemId":null,"number":null,"itemTitle":null,"message":"I take over the on-call duty next month.","status":"open","role":null,"decidedBy":null,"decidedAt":null,"createdAt":"2026-10-01T09:30:00.000Z"}}}},"400":{"description":"`invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}},"404":{"description":"`notFound`: Not found. `requestNotFound`: The access request does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"requestNotFound":{"value":{"type":"urn:lunedo:problem:requestNotFound","title":"The access request does not exist","status":404,"code":"requestNotFound"}}}}}}}}},"/api/v1/access-requests/{requestId}/decide":{"post":{"operationId":"accessRequests.decide","summary":"Decide an access request","description":"Approves a request with a role or declines it. Space requests need space admin rights, page requests the right to share the page. The requester is notified.\n\nRequires the permission `instance.content.view` on the instance.","tags":["Access requests"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"requestId","in":"path","required":true,"description":"ID of the access request.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"approve":{"type":"boolean","const":true,"description":"Approve the request."},"role":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Role to give. Pages can get `reader`, `commenter` or `editor`."},"includeDescendants":{"default":false,"description":"For pages: also give access to the pages below.","type":"boolean"}},"required":["approve","role"],"additionalProperties":false,"description":"Approval with a role."},{"type":"object","properties":{"approve":{"type":"boolean","const":false,"description":"Decline the request."}},"required":["approve"],"additionalProperties":false,"description":"Decline."}],"description":"The decision."},"example":{"approve":true,"role":"reader"}}}},"responses":{"200":{"description":"The decided request.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the request."},"requester":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]},"email":{"description":"E-mail address, when the caller may see it.","type":["string","null"]}},"required":["id","name","email"],"additionalProperties":false,"description":"Who asks."},"target":{"type":"string","description":"Whether the request is for a whole space or for a page. New values can be added in later versions; handle unknown values.","x-extensible-enum":["space","page"]},"spaceId":{"anyOf":[{"type":"string","format":"uuid","description":"The space."},{"type":"null"}],"description":"The space, or null when the requester cannot see the page the request is for."},"spaceName":{"type":"string","description":"Name of the space; empty when the requester cannot see it."},"itemId":{"anyOf":[{"type":"string","format":"uuid","description":"The page."},{"type":"null"}],"description":"The page; null for the whole space and when the requester cannot see the page."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the page in the addresses of the app."},{"type":"null"}],"description":"Number of the page in the addresses of the app, when the caller may see its title; null for the whole space."},"itemTitle":{"description":"Title of the page, when the caller may see it.","type":["string","null"]},"message":{"type":"string","description":"Message of the requester."},"status":{"type":"string","description":"`satisfied` means the person got access another way. New values can be added in later versions; handle unknown values.","x-extensible-enum":["open","approved","declined","withdrawn","satisfied"]},"role":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"]},{"type":"null"}],"description":"The role given when approved."},"decidedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who decided; null when the requester cannot see the page."},"decidedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When it was decided. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When it was sent. ISO 8601 timestamp in UTC."}},"required":["id","requester","target","spaceId","spaceName","itemId","number","itemTitle","message","status","role","decidedBy","decidedAt","createdAt"],"additionalProperties":false,"description":"A request for access to a space or page."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","requester":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a22","name":"Mia Kranz","email":"mia.kranz@example.org"},"target":"space","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a00","spaceName":"IT Operations","itemId":null,"number":null,"itemTitle":null,"message":"I take over the on-call duty next month.","status":"open","role":null,"decidedBy":null,"decidedAt":null,"createdAt":"2026-10-01T09:30:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidRole`: The role cannot be given here.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidRole":{"value":{"type":"urn:lunedo:problem:invalidRole","title":"The role cannot be given here","status":400,"code":"invalidRole"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `selfExtension`: Nobody can extend their own permissions. `shareBeyondOwnAccess`: A share cannot reach further than your own access.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"selfExtension":{"value":{"type":"urn:lunedo:problem:selfExtension","title":"Nobody can extend their own permissions","status":403,"code":"selfExtension"}},"shareBeyondOwnAccess":{"value":{"type":"urn:lunedo:problem:shareBeyondOwnAccess","title":"A share cannot reach further than your own access","status":403,"code":"shareBeyondOwnAccess"}}}}}},"404":{"description":"`notFound`: Not found. `requestNotFound`: The access request does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"requestNotFound":{"value":{"type":"urn:lunedo:problem:requestNotFound","title":"The access request does not exist","status":404,"code":"requestNotFound"}}}}}},"409":{"description":"`lastSpaceAdmin`: A space needs at least one space admin. `requestClosed`: The access request was already decided.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"lastSpaceAdmin":{"value":{"type":"urn:lunedo:problem:lastSpaceAdmin","title":"A space needs at least one space admin","status":409,"code":"lastSpaceAdmin"}},"requestClosed":{"value":{"type":"urn:lunedo:problem:requestClosed","title":"The access request was already decided","status":409,"code":"requestClosed"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/access-requests/{requestId}/withdraw":{"post":{"operationId":"accessRequests.withdraw","summary":"Withdraw your access request","description":"Withdraws an open request of the caller.\n\nRequires the permission `instance.content.view` on the instance. Needs a signed-in session; API tokens are refused.","tags":["Access requests"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"sessionCookie":[]}],"parameters":[{"name":"requestId","in":"path","required":true,"description":"ID of the access request.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}},"404":{"description":"`notFound`: Not found. `requestNotFound`: The access request does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"requestNotFound":{"value":{"type":"urn:lunedo:problem:requestNotFound","title":"The access request does not exist","status":404,"code":"requestNotFound"}}}}}},"409":{"description":"`requestClosed`: The access request was already decided.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"requestClosed":{"value":{"type":"urn:lunedo:problem:requestClosed","title":"The access request was already decided","status":409,"code":"requestClosed"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/access-requests/mine":{"get":{"operationId":"accessRequests.mine","summary":"List your access requests","description":"Lists the caller's requests, newest first.\n\nRequires the permission `instance.content.view` on the instance. Needs a signed-in session; API tokens are refused.","tags":["Access requests"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"sessionCookie":[]}],"responses":{"200":{"description":"The requests.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the request."},"requester":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]},"email":{"description":"E-mail address, when the caller may see it.","type":["string","null"]}},"required":["id","name","email"],"additionalProperties":false,"description":"Who asks."},"target":{"type":"string","description":"Whether the request is for a whole space or for a page. New values can be added in later versions; handle unknown values.","x-extensible-enum":["space","page"]},"spaceId":{"anyOf":[{"type":"string","format":"uuid","description":"The space."},{"type":"null"}],"description":"The space, or null when the requester cannot see the page the request is for."},"spaceName":{"type":"string","description":"Name of the space; empty when the requester cannot see it."},"itemId":{"anyOf":[{"type":"string","format":"uuid","description":"The page."},{"type":"null"}],"description":"The page; null for the whole space and when the requester cannot see the page."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the page in the addresses of the app."},{"type":"null"}],"description":"Number of the page in the addresses of the app, when the caller may see its title; null for the whole space."},"itemTitle":{"description":"Title of the page, when the caller may see it.","type":["string","null"]},"message":{"type":"string","description":"Message of the requester."},"status":{"type":"string","description":"`satisfied` means the person got access another way. New values can be added in later versions; handle unknown values.","x-extensible-enum":["open","approved","declined","withdrawn","satisfied"]},"role":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"]},{"type":"null"}],"description":"The role given when approved."},"decidedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who decided; null when the requester cannot see the page."},"decidedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When it was decided. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When it was sent. ISO 8601 timestamp in UTC."}},"required":["id","requester","target","spaceId","spaceName","itemId","number","itemTitle","message","status","role","decidedBy","decidedAt","createdAt"],"additionalProperties":false,"description":"A request for access to a space or page."},"description":"Requests, newest first."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","requester":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a22","name":"Mia Kranz","email":"mia.kranz@example.org"},"target":"space","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a00","spaceName":"IT Operations","itemId":null,"number":null,"itemTitle":null,"message":"I take over the on-call duty next month.","status":"open","role":null,"decidedBy":null,"decidedAt":null,"createdAt":"2026-10-01T09:30:00.000Z"}]}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}}}}},"/api/v1/announcements":{"get":{"operationId":"announcements.shown","summary":"List the announcements shown to you","description":"Returns the announcements of the instance and of the caller's organizations that have started and not ended. Scheduled announcements appear once they start; administrators see them in the announcement settings. Hide dismissed information.\n\nRequires the permission `instance.content.view` on the instance. Needs a signed-in session; API tokens are refused.","tags":["Announcements"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"sessionCookie":[]}],"responses":{"200":{"description":"The announcements.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the announcement. It stays the same when the announcement is changed."},"scope":{"type":"string","enum":["instance","organization"],"description":"Who set it."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The organization, or null for the instance."},"version":{"type":"string","format":"uuid","description":"Changes with every change of the announcement."},"severity":{"type":"string","enum":["information","warning"],"description":"`information` can be dismissed by each person until the announcement changes; `warning` stays until its end."},"text":{"type":"string","description":"The text."},"link":{"anyOf":[{"type":"object","properties":{"url":{"type":"string","maxLength":2000,"description":"Address starting with https:// or http://."},"label":{"type":"string","maxLength":60,"description":"Text of the link."}},"required":["url","label"],"additionalProperties":false,"description":"A link shown after the text."},{"type":"null"}],"description":"The link, or null."},"startsAt":{"type":"string","format":"date-time","description":"When it starts to show. ISO 8601 timestamp in UTC."},"endsAt":{"type":"string","format":"date-time","description":"When it stops showing. ISO 8601 timestamp in UTC."},"dismissed":{"type":"boolean","description":"Whether the caller dismissed this version."}},"required":["id","scope","organizationId","version","severity","text","link","startsAt","endsAt","dismissed"],"additionalProperties":false,"description":"An announcement."},"description":"Announcements of the instance and of the caller's organizations that have started and not ended. The instance announcement comes first."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","scope":"organization","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a01","version":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a41","severity":"information","text":"New: search in attachments. PDF, Word and Excel files are now searchable.","link":{"url":"https://wiki.example.org/spaces/ENG/blog","label":"Read the post"},"startsAt":"2026-10-14T08:00:00.000Z","endsAt":"2026-10-21T08:00:00.000Z","dismissed":false}]}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}}}}},"/api/v1/announcements/{announcementId}/dismiss":{"post":{"operationId":"announcements.dismiss","summary":"Dismiss an announcement","description":"Hides an information announcement for you until it changes. Warnings cannot be dismissed; they disappear at their end.\n\nRequires the permission `instance.content.view` on the instance. Needs a signed-in session; API tokens are refused.","tags":["Announcements"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"sessionCookie":[]}],"parameters":[{"name":"announcementId","in":"path","required":true,"description":"ID of the announcement.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"string","format":"uuid","description":"The version that was shown."}},"required":["version"],"additionalProperties":false,"description":"The version to dismiss."},"example":{"version":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a41"}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`announcementChanged`: The announcement changed in the meantime. `announcementNotDismissible`: A warning cannot be dismissed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"announcementChanged":{"value":{"type":"urn:lunedo:problem:announcementChanged","title":"The announcement changed in the meantime","status":409,"code":"announcementChanged"}},"announcementNotDismissible":{"value":{"type":"urn:lunedo:problem:announcementNotDismissible","title":"A warning cannot be dismissed","status":409,"code":"announcementNotDismissible"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/articles/{itemId}":{"get":{"operationId":"knowledgeBases.article","summary":"Get an article with its sections","description":"Returns the published version of an article with its number, address, categories and semantic sections, for programs such as chatbots and migration scripts.\n\nRequires the permission `item.view` on the item in `itemId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the article.","schema":{"type":"string","format":"uuid"}},{"name":"draft","in":"query","required":false,"description":"`true` returns the current draft instead of the published version. Only for editors of the article.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"The article.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the article."},"spaceId":{"type":"string","format":"uuid","description":"ID of the knowledge base."},"title":{"type":"string","description":"Title of the article."},"type":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Type of the article, or null."},"number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the article. It is unique on the instance, shared with pages, folders, blog posts and whiteboards, and never reused. It stays when the article moves."},"slug":{"type":"string","description":"Short form of the title for addresses. The address of an article is `<number>-<slug>`."},"categoryPath":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the category."},"title":{"type":"string","description":"Title of the category."}},"required":["id","title"],"additionalProperties":false,"description":"A category."},"description":"Folders above the article from the top level down, as far as the caller can see them. Empty at the top level."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of the article, or null."},"ownerName":{"description":"Name of the owner, or null when the caller may not see it.","type":["string","null"]},"published":{"type":"boolean","description":"Whether the article was published. Only editors see unpublished articles."},"contentUpdatedAt":{"type":"string","format":"date-time","description":"When the content last changed. ISO 8601 timestamp in UTC."},"language":{"type":"string","description":"Language of the article."},"translationOf":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The original article when this is a translation, or null."},"translations":{"type":"array","items":{"type":"object","properties":{"language":{"type":"string","description":"Language as a two-letter code such as `de` or `en`."},"itemId":{"type":"string","format":"uuid","description":"ID of the translation."},"state":{"type":"string","enum":["original","current","outdated","unpublished","missing"],"description":"`original`: the article in the default language. `current`: published after its original. `outdated`: the original was published after it. `unpublished`: never published. `missing`: no translation yet."}},"required":["language","itemId","state"],"additionalProperties":false,"description":"A translation of the article."},"description":"Translations of an original article the caller can read. Empty for translations."},"spaceKey":{"type":"string","description":"Key of the knowledge base."},"lead":{"type":"string","description":"Short introduction below the title."},"templateId":{"description":"Template the article was created from, or null.","type":["string","null"]},"contactEmail":{"anyOf":[{"type":"string","maxLength":254},{"type":"null"}],"description":"Contact address that applies to the article, or null."},"version":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the published version that is returned, or null for a draft or an unpublished article."},"sections":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the section, such as `steps` or `cause`. It keeps its meaning in every language."},"title":{"type":"string","description":"Heading of the section."},"icon":{"description":"Name of a Lucide icon, or null.","type":["string","null"]},"text":{"type":"string","description":"Plain text of the section."},"html":{"type":"string","description":"Content of the section as HTML. Images point to their display version in the API, links to other articles to the portal."},"content":{"type":"array","items":{"$ref":"#/components/schemas/Schema113ae44d8375"},"description":"Content of the section as ProseMirror JSON nodes."}},"required":["key","title","icon","text","html","content"],"additionalProperties":false,"description":"A section of the article."},"description":"Semantic sections of the article in document order. Empty for an article written without sections."},"document":{"anyOf":[{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schemafbc378f59d82"},{"type":"null"}],"description":"Whole content as ProseMirror JSON, or null for an article that was never published."},"images":{"type":"array","items":{"type":"object","properties":{"attachmentId":{"type":"string","format":"uuid","description":"ID of the image file."},"name":{"type":"string","description":"File name."},"alt":{"type":"string","description":"Alternative text, empty when the author gave none."},"url":{"type":"string","description":"Address of the display version in the API; send the same token to fetch it."}},"required":["attachmentId","name","alt","url"],"additionalProperties":false,"description":"An image of the article."},"description":"Images in the content, in document order."},"draft":{"type":"boolean","description":"Whether this is the current draft instead of the published version."},"publishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the article was published for the first time, or null. ISO 8601 timestamp in UTC."},"versionPublishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the returned version was published, or null for a draft. ISO 8601 timestamp in UTC."},"lastReviewedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the article was last reviewed while a review interval applies, or null. ISO 8601 timestamp in UTC."},"portalUrl":{"description":"Address of the article in the portal, in its language, or null when it is not published.","type":["string","null"]}},"required":["id","spaceId","title","type","number","slug","categoryPath","ownerId","ownerName","published","contentUpdatedAt","language","translationOf","translations","spaceKey","lead","templateId","contactEmail","version","sections","document","images","draft","publishedAt","versionPublishedAt","lastReviewedAt","portalUrl"],"additionalProperties":false,"description":"An article with its sections, readable by programs."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a61","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","title":"Set up the VPN connection","type":"howTo","number":1123,"slug":"set-up-the-vpn-connection","categoryPath":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","title":"IT"}],"ownerId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","ownerName":"Anna Weber","published":true,"contentUpdatedAt":"2026-10-05T08:00:00.000Z","language":"de","translationOf":null,"translations":[{"language":"en","itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a62","state":"outdated"}],"spaceKey":"HELP","lead":"Work from home with the company network.","templateId":"builtin:article-how-to","contactEmail":"it@example.org","version":3,"sections":[{"key":"steps","title":"Steps","icon":"list-ordered","text":"Open the VPN client.","html":"<p>Open the VPN client.</p>","content":[{"type":"paragraph","content":[{"type":"text","text":"Open the VPN client."}]}]}],"document":null,"images":[],"draft":false,"publishedAt":"2026-09-01T08:00:00.000Z","versionPublishedAt":"2026-10-05T08:00:00.000Z","lastReviewedAt":null,"portalUrl":"https://wiki.example.org/help/help/1123-set-up-the-vpn-connection"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`draftNotVisible`: Only editors see the draft. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"draftNotVisible":{"value":{"type":"urn:lunedo:problem:draftNotVisible","title":"Only editors see the draft","status":403,"code":"draftNotVisible"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/articles/{itemId}/draft":{"put":{"operationId":"articleApi.saveDraft","summary":"Save a draft of an article","description":"Saves title and sections as the draft of the article without publishing it; a person publishes it in Lunedo, or a caller that may publish. Type, category and lead change at once for readers, so they need permission to publish once the article is published.\n\nRequires the permission `item.editDraft` on the item in `itemId`.","tags":["Knowledge base articles"],"x-lunedo-permission":{"action":"item.editDraft","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the article.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"description":"Title of the article.","type":"string","minLength":1,"maxLength":255},"lead":{"description":"Short introduction below the title.","type":"string","maxLength":1000},"type":{"description":"Type of the article, or null for none.","anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}]},"categoryId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Category or subcategory to place the article in, or null for the top level."},"sections":{"description":"Sections in order. They replace the whole content of the draft.","maxItems":50,"type":"array","items":{"type":"object","properties":{"key":{"type":"string","pattern":"^[a-z][a-zA-Z0-9]{0,39}$","description":"Key of the section, such as `steps` or `cause`."},"title":{"description":"Heading of the section.","type":"string","maxLength":255},"icon":{"description":"Name of a Lucide icon, or null.","anyOf":[{"type":"string","maxLength":60},{"type":"null"}]},"markdown":{"description":"Content as Markdown. Images uploaded to the article are referenced by their file name, for example `![Login screen](login.png)`.","type":"string","maxLength":500000},"content":{"description":"Content as ProseMirror JSON nodes instead of Markdown. Images reference `attachmentId`.","maxItems":10000,"type":"array","items":{"$ref":"#/components/schemas/Schema113ae44d8375"}}},"required":["key"],"additionalProperties":false,"description":"A section of the article."}},"versionNote":{"description":"Note shown in the history, for example who checked the content. Stored with the draft and used when it is published.","type":"string","maxLength":1000}},"additionalProperties":false,"description":"Changes saved as the draft of the article."},"example":{"sections":[{"key":"steps","title":"Steps","markdown":"1. Open the VPN client.\n2. Sign in with the new code."}],"versionNote":"Checked by Anna Huber in the help assistant"}}}},"responses":{"200":{"description":"The draft.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the article."},"spaceId":{"type":"string","format":"uuid","description":"ID of the knowledge base."},"title":{"type":"string","description":"Title of the article."},"type":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Type of the article, or null."},"number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the article. It is unique on the instance, shared with pages, folders, blog posts and whiteboards, and never reused. It stays when the article moves."},"slug":{"type":"string","description":"Short form of the title for addresses. The address of an article is `<number>-<slug>`."},"categoryPath":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the category."},"title":{"type":"string","description":"Title of the category."}},"required":["id","title"],"additionalProperties":false,"description":"A category."},"description":"Folders above the article from the top level down, as far as the caller can see them. Empty at the top level."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of the article, or null."},"ownerName":{"description":"Name of the owner, or null when the caller may not see it.","type":["string","null"]},"published":{"type":"boolean","description":"Whether the article was published. Only editors see unpublished articles."},"contentUpdatedAt":{"type":"string","format":"date-time","description":"When the content last changed. ISO 8601 timestamp in UTC."},"language":{"type":"string","description":"Language of the article."},"translationOf":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The original article when this is a translation, or null."},"translations":{"type":"array","items":{"type":"object","properties":{"language":{"type":"string","description":"Language as a two-letter code such as `de` or `en`."},"itemId":{"type":"string","format":"uuid","description":"ID of the translation."},"state":{"type":"string","enum":["original","current","outdated","unpublished","missing"],"description":"`original`: the article in the default language. `current`: published after its original. `outdated`: the original was published after it. `unpublished`: never published. `missing`: no translation yet."}},"required":["language","itemId","state"],"additionalProperties":false,"description":"A translation of the article."},"description":"Translations of an original article the caller can read. Empty for translations."},"spaceKey":{"type":"string","description":"Key of the knowledge base."},"lead":{"type":"string","description":"Short introduction below the title."},"templateId":{"description":"Template the article was created from, or null.","type":["string","null"]},"contactEmail":{"anyOf":[{"type":"string","maxLength":254},{"type":"null"}],"description":"Contact address that applies to the article, or null."},"version":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the published version that is returned, or null for a draft or an unpublished article."},"sections":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the section, such as `steps` or `cause`. It keeps its meaning in every language."},"title":{"type":"string","description":"Heading of the section."},"icon":{"description":"Name of a Lucide icon, or null.","type":["string","null"]},"text":{"type":"string","description":"Plain text of the section."},"html":{"type":"string","description":"Content of the section as HTML. Images point to their display version in the API, links to other articles to the portal."},"content":{"type":"array","items":{"$ref":"#/components/schemas/Schema113ae44d8375"},"description":"Content of the section as ProseMirror JSON nodes."}},"required":["key","title","icon","text","html","content"],"additionalProperties":false,"description":"A section of the article."},"description":"Semantic sections of the article in document order. Empty for an article written without sections."},"document":{"anyOf":[{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schemafbc378f59d82"},{"type":"null"}],"description":"Whole content as ProseMirror JSON, or null for an article that was never published."},"images":{"type":"array","items":{"type":"object","properties":{"attachmentId":{"type":"string","format":"uuid","description":"ID of the image file."},"name":{"type":"string","description":"File name."},"alt":{"type":"string","description":"Alternative text, empty when the author gave none."},"url":{"type":"string","description":"Address of the display version in the API; send the same token to fetch it."}},"required":["attachmentId","name","alt","url"],"additionalProperties":false,"description":"An image of the article."},"description":"Images in the content, in document order."},"draft":{"type":"boolean","description":"Whether this is the current draft instead of the published version."},"publishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the article was published for the first time, or null. ISO 8601 timestamp in UTC."},"versionPublishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the returned version was published, or null for a draft. ISO 8601 timestamp in UTC."},"lastReviewedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the article was last reviewed while a review interval applies, or null. ISO 8601 timestamp in UTC."},"portalUrl":{"description":"Address of the article in the portal, in its language, or null when it is not published.","type":["string","null"]}},"required":["id","spaceId","title","type","number","slug","categoryPath","ownerId","ownerName","published","contentUpdatedAt","language","translationOf","translations","spaceKey","lead","templateId","contactEmail","version","sections","document","images","draft","publishedAt","versionPublishedAt","lastReviewedAt","portalUrl"],"additionalProperties":false,"description":"An article with its sections, readable by programs."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a61","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","title":"Set up the VPN connection","type":"howTo","number":1123,"slug":"set-up-the-vpn-connection","categoryPath":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","title":"IT"}],"ownerId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","ownerName":"Anna Weber","published":true,"contentUpdatedAt":"2026-10-05T08:00:00.000Z","language":"de","translationOf":null,"translations":[{"language":"en","itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a62","state":"outdated"}],"spaceKey":"HELP","lead":"Work from home with the company network.","templateId":"builtin:article-how-to","contactEmail":"it@example.org","version":3,"sections":[{"key":"steps","title":"Steps","icon":"list-ordered","text":"Open the VPN client.","html":"<p>Open the VPN client.</p>","content":[{"type":"paragraph","content":[{"type":"text","text":"Open the VPN client."}]}]}],"document":null,"images":[],"draft":false,"publishedAt":"2026-09-01T08:00:00.000Z","versionPublishedAt":"2026-10-05T08:00:00.000Z","lastReviewedAt":null,"portalUrl":"https://wiki.example.org/help/help/1123-set-up-the-vpn-connection"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidDocument`: The document does not match the editor schema. `invalidInput`: The request is not valid. `invalidNote`: The note is too long.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidDocument":{"value":{"type":"urn:lunedo:problem:invalidDocument","title":"The document does not match the editor schema","status":400,"code":"invalidDocument"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidNote":{"value":{"type":"urn:lunedo:problem:invalidNote","title":"The note is too long","status":400,"code":"invalidNote"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `publishNotAllowed`: Publishing is not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"publishNotAllowed":{"value":{"type":"urn:lunedo:problem:publishNotAllowed","title":"Publishing is not allowed","status":403,"code":"publishNotAllowed"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`moveChangesAccess`: The move changes who can access the content. `notArticle`: The item is not an article of a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"moveChangesAccess":{"value":{"type":"urn:lunedo:problem:moveChangesAccess","title":"The move changes who can access the content","status":409,"code":"moveChangesAccess"}},"notArticle":{"value":{"type":"urn:lunedo:problem:notArticle","title":"The item is not an article of a knowledge base","status":409,"code":"notArticle"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/articles/{itemId}/hidden-sources":{"delete":{"operationId":"reviews.removeHiddenSources","summary":"Remove the source pages of an article the caller cannot read","description":"Removes the links to all source pages the caller cannot read. People who can read such a page can link it again. Audited.\n\nRequires the permission `item.edit` on the item in `itemId`.","tags":["Knowledge base reviews"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the article.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The source pages the caller cannot read after the change.","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Number of linked source pages the caller cannot read."},"changed":{"type":"boolean","description":"Whether one of them changed after the last review of the article."}},"required":["count","changed"],"additionalProperties":false,"description":"Source pages the caller cannot read, without their titles."},"example":{"count":0,"changed":false}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notArticle`: The item is not an article of a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notArticle":{"value":{"type":"urn:lunedo:problem:notArticle","title":"The item is not an article of a knowledge base","status":409,"code":"notArticle"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"get":{"operationId":"reviews.hiddenSources","summary":"Count the source pages of an article the caller cannot read","description":"Tells editors of the article how many linked source pages they cannot read, without titles, so that they can remove links nobody can maintain any more.\n\nRequires the permission `item.edit` on the item in `itemId`.","tags":["Knowledge base reviews"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the article.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The source pages the caller cannot read.","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Number of linked source pages the caller cannot read."},"changed":{"type":"boolean","description":"Whether one of them changed after the last review of the article."}},"required":["count","changed"],"additionalProperties":false,"description":"Source pages the caller cannot read, without their titles."},"example":{"count":1,"changed":true}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notArticle`: The item is not an article of a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notArticle":{"value":{"type":"urn:lunedo:problem:notArticle","title":"The item is not an article of a knowledge base","status":409,"code":"notArticle"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/articles/{itemId}/images":{"post":{"operationId":"articleApi.addImage","summary":"Upload an image to an article","description":"Adds an image to the draft of an article. Send the bytes with `Content-Type: application/octet-stream`. Sections of a draft reference it by its name.\n\nRequires the permission `item.editDraft` on the item in `itemId`.","tags":["Knowledge base articles"],"x-lunedo-permission":{"action":"item.editDraft","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the article.","schema":{"type":"string","format":"uuid"}},{"name":"name","in":"query","required":true,"description":"File name. Sections reference the image by it. The same name replaces the image.","schema":{"type":"string","minLength":1,"maxLength":1020}}],"requestBody":{"required":true,"description":"The bytes of the image.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"201":{"description":"The image.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the attachment."},"itemId":{"type":"string","format":"uuid","description":"Page or blog post the file is attached to."},"name":{"type":"string","description":"File name of the current version."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the current version in bytes."},"contentType":{"type":"string","description":"Media type, decided from the content of the file."},"preview":{"type":"string","description":"How the file can be previewed; `none` offers only the download. New values can be added in later versions; handle unknown values.","x-extensible-enum":["image","pdf","video","audio","text","code","markdown","csv","svg","word","excel","none"]},"inline":{"type":"boolean","description":"Whether browsers may show the file directly: images, video and audio."},"tooLargeForPreview":{"type":"boolean","description":"Whether the image has more than 100 megapixels. Such images get no smaller version; pages and previews show them as a file that opens in full size."},"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the current version."},"versions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of stored versions."},"draft":{"anyOf":[{"type":"string","x-extensible-enum":["added","changed","deleted"]},{"type":"null"}],"description":"Only for people who can edit the page: `added` when readers do not see the file until the next publication, `changed` when readers still see an earlier version, `deleted` when the file was deleted in the draft and readers still see it until the next publication; restore it to keep it. Null when readers see this version. New values can be added in later versions; handle unknown values."},"uploadedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who uploaded the current version."},"uploadedAt":{"type":"string","format":"date-time","description":"When the current version was uploaded. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the file was first attached. ISO 8601 timestamp in UTC."}},"required":["id","itemId","name","size","contentType","preview","inline","tooLargeForPreview","version","versions","draft","uploadedBy","uploadedAt","createdAt"],"additionalProperties":false,"description":"A file attached to a page or blog post."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","name":"network-diagram.png","size":48213,"contentType":"image/png","preview":"image","inline":true,"tooLargeForPreview":false,"version":2,"versions":2,"draft":null,"uploadedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"uploadedAt":"2026-10-01T09:30:00.000Z","createdAt":"2026-09-28T14:02:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidFileName`: The file name is not valid. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidFileName":{"value":{"type":"urn:lunedo:problem:invalidFileName","title":"The file name is not valid","status":400,"code":"invalidFileName"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notArticle`: The item is not an article of a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notArticle":{"value":{"type":"urn:lunedo:problem:notArticle","title":"The item is not an article of a knowledge base","status":409,"code":"notArticle"}}}}}},"413":{"description":"`fileTooLarge`: The file is larger than allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"fileTooLarge":{"value":{"type":"urn:lunedo:problem:fileTooLarge","title":"The file is larger than allowed","status":413,"code":"fileTooLarge"}}}}}},"415":{"description":"`unsupportedMediaType`: The request body has an unsupported type.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unsupportedMediaType":{"value":{"type":"urn:lunedo:problem:unsupportedMediaType","title":"The request body has an unsupported type","status":415,"code":"unsupportedMediaType"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}},"507":{"description":"`storageFull`: Storage is almost full.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"storageFull":{"value":{"type":"urn:lunedo:problem:storageFull","title":"Storage is almost full","status":507,"code":"storageFull"}}}}}}}}},"/api/v1/articles/{itemId}/publish":{"post":{"operationId":"articleApi.publish","summary":"Publish an article","description":"Publishes the current draft as a new version with the caller as its author. The version note, or the one saved with the draft, appears in the history. Audited.\n\nRequires the permission `item.publish` on the item in `itemId`.","tags":["Knowledge base articles"],"x-lunedo-permission":{"action":"item.publish","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the article.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"versionNote":{"description":"Note shown in the history, for example who checked the content. Stored with the draft and used when it is published.","type":"string","maxLength":1000}},"additionalProperties":false,"description":"The publication."},"example":{"versionNote":"Checked by Anna Huber in the help assistant"}}}},"responses":{"200":{"description":"The published article.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the article."},"spaceId":{"type":"string","format":"uuid","description":"ID of the knowledge base."},"title":{"type":"string","description":"Title of the article."},"type":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Type of the article, or null."},"number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the article. It is unique on the instance, shared with pages, folders, blog posts and whiteboards, and never reused. It stays when the article moves."},"slug":{"type":"string","description":"Short form of the title for addresses. The address of an article is `<number>-<slug>`."},"categoryPath":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the category."},"title":{"type":"string","description":"Title of the category."}},"required":["id","title"],"additionalProperties":false,"description":"A category."},"description":"Folders above the article from the top level down, as far as the caller can see them. Empty at the top level."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of the article, or null."},"ownerName":{"description":"Name of the owner, or null when the caller may not see it.","type":["string","null"]},"published":{"type":"boolean","description":"Whether the article was published. Only editors see unpublished articles."},"contentUpdatedAt":{"type":"string","format":"date-time","description":"When the content last changed. ISO 8601 timestamp in UTC."},"language":{"type":"string","description":"Language of the article."},"translationOf":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The original article when this is a translation, or null."},"translations":{"type":"array","items":{"type":"object","properties":{"language":{"type":"string","description":"Language as a two-letter code such as `de` or `en`."},"itemId":{"type":"string","format":"uuid","description":"ID of the translation."},"state":{"type":"string","enum":["original","current","outdated","unpublished","missing"],"description":"`original`: the article in the default language. `current`: published after its original. `outdated`: the original was published after it. `unpublished`: never published. `missing`: no translation yet."}},"required":["language","itemId","state"],"additionalProperties":false,"description":"A translation of the article."},"description":"Translations of an original article the caller can read. Empty for translations."},"spaceKey":{"type":"string","description":"Key of the knowledge base."},"lead":{"type":"string","description":"Short introduction below the title."},"templateId":{"description":"Template the article was created from, or null.","type":["string","null"]},"contactEmail":{"anyOf":[{"type":"string","maxLength":254},{"type":"null"}],"description":"Contact address that applies to the article, or null."},"version":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the published version that is returned, or null for a draft or an unpublished article."},"sections":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the section, such as `steps` or `cause`. It keeps its meaning in every language."},"title":{"type":"string","description":"Heading of the section."},"icon":{"description":"Name of a Lucide icon, or null.","type":["string","null"]},"text":{"type":"string","description":"Plain text of the section."},"html":{"type":"string","description":"Content of the section as HTML. Images point to their display version in the API, links to other articles to the portal."},"content":{"type":"array","items":{"$ref":"#/components/schemas/Schema113ae44d8375"},"description":"Content of the section as ProseMirror JSON nodes."}},"required":["key","title","icon","text","html","content"],"additionalProperties":false,"description":"A section of the article."},"description":"Semantic sections of the article in document order. Empty for an article written without sections."},"document":{"anyOf":[{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schemafbc378f59d82"},{"type":"null"}],"description":"Whole content as ProseMirror JSON, or null for an article that was never published."},"images":{"type":"array","items":{"type":"object","properties":{"attachmentId":{"type":"string","format":"uuid","description":"ID of the image file."},"name":{"type":"string","description":"File name."},"alt":{"type":"string","description":"Alternative text, empty when the author gave none."},"url":{"type":"string","description":"Address of the display version in the API; send the same token to fetch it."}},"required":["attachmentId","name","alt","url"],"additionalProperties":false,"description":"An image of the article."},"description":"Images in the content, in document order."},"draft":{"type":"boolean","description":"Whether this is the current draft instead of the published version."},"publishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the article was published for the first time, or null. ISO 8601 timestamp in UTC."},"versionPublishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the returned version was published, or null for a draft. ISO 8601 timestamp in UTC."},"lastReviewedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the article was last reviewed while a review interval applies, or null. ISO 8601 timestamp in UTC."},"portalUrl":{"description":"Address of the article in the portal, in its language, or null when it is not published.","type":["string","null"]}},"required":["id","spaceId","title","type","number","slug","categoryPath","ownerId","ownerName","published","contentUpdatedAt","language","translationOf","translations","spaceKey","lead","templateId","contactEmail","version","sections","document","images","draft","publishedAt","versionPublishedAt","lastReviewedAt","portalUrl"],"additionalProperties":false,"description":"An article with its sections, readable by programs."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a61","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","title":"Set up the VPN connection","type":"howTo","number":1123,"slug":"set-up-the-vpn-connection","categoryPath":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","title":"IT"}],"ownerId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","ownerName":"Anna Weber","published":true,"contentUpdatedAt":"2026-10-05T08:00:00.000Z","language":"de","translationOf":null,"translations":[{"language":"en","itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a62","state":"outdated"}],"spaceKey":"HELP","lead":"Work from home with the company network.","templateId":"builtin:article-how-to","contactEmail":"it@example.org","version":3,"sections":[{"key":"steps","title":"Steps","icon":"list-ordered","text":"Open the VPN client.","html":"<p>Open the VPN client.</p>","content":[{"type":"paragraph","content":[{"type":"text","text":"Open the VPN client."}]}]}],"document":null,"images":[],"draft":false,"publishedAt":"2026-09-01T08:00:00.000Z","versionPublishedAt":"2026-10-05T08:00:00.000Z","lastReviewedAt":null,"portalUrl":"https://wiki.example.org/help/help/1123-set-up-the-vpn-connection"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidNote`: The note is too long.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidNote":{"value":{"type":"urn:lunedo:problem:invalidNote","title":"The note is too long","status":400,"code":"invalidNote"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notArticle`: The item is not an article of a knowledge base. `requiredSectionsEmpty`: Required sections are empty.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notArticle":{"value":{"type":"urn:lunedo:problem:notArticle","title":"The item is not an article of a knowledge base","status":409,"code":"notArticle"}},"requiredSectionsEmpty":{"value":{"type":"urn:lunedo:problem:requiredSectionsEmpty","title":"Required sections are empty","status":409,"code":"requiredSectionsEmpty"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/articles/{itemId}/review":{"get":{"operationId":"reviews.article","summary":"Get the review state of an article","description":"Returns the interval, the last review and the next due date of an article.\n\nRequires the permission `item.view` on the item in `itemId`.","tags":["Knowledge base reviews"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the article.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The review state.","content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"ID of the article."},"intervalMonths":{"anyOf":[{"anyOf":[{"type":"number","const":0},{"anyOf":[{"type":"number","const":3},{"type":"number","const":6},{"type":"number","const":12}]}],"description":"Review interval in months."},{"type":"null"}],"description":"Interval set on the article itself: 0 for no reviews, or null when it uses the knowledge base's."},"effectiveIntervalMonths":{"anyOf":[{"anyOf":[{"type":"number","const":3},{"type":"number","const":6},{"type":"number","const":12}],"description":"Review interval in months."},{"type":"null"}],"description":"Interval that applies, or null when none."},"inherited":{"type":"boolean","description":"Whether the interval comes from the knowledge base."},"publishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the article was first published, or null. ISO 8601 timestamp in UTC."},"reviewedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the article was last marked as reviewed, or null. ISO 8601 timestamp in UTC."},"reviewedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the person."},"name":{"description":"Name of the person, or null when the caller may not see the person.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null without one. Changes whenever the picture changes; load the picture from `GET /api/v1/accounts/{accountId}/picture`.","type":["string","null"]}},"required":["id","name","pictureRef"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who reviewed it last, or null."},"dueAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the next review is due, or null when no interval applies. ISO 8601 timestamp in UTC."},"sourceChangedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When a source page changed after the last review, or null. ISO 8601 timestamp in UTC."},"state":{"type":"string","enum":["overdue","sourceChanged","dueSoon","current","off"],"description":"`overdue`: the interval has passed. `sourceChanged`: a source page changed since the last review. `dueSoon`: due within 30 days. `current`: reviewed within the interval. `off`: no interval applies."}},"required":["itemId","intervalMonths","effectiveIntervalMonths","inherited","publishedAt","reviewedAt","reviewedBy","dueAt","sourceChangedAt","state"],"additionalProperties":false,"description":"Review state of an article."},"example":{"itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a50","intervalMonths":null,"effectiveIntervalMonths":6,"inherited":true,"publishedAt":"2026-03-02T09:00:00.000Z","reviewedAt":"2026-10-02T09:00:00.000Z","reviewedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Weber","pictureRef":null},"dueAt":"2027-04-02T09:00:00.000Z","sourceChangedAt":null,"state":"current"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notArticle`: The item is not an article of a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notArticle":{"value":{"type":"urn:lunedo:problem:notArticle","title":"The item is not an article of a knowledge base","status":409,"code":"notArticle"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/articles/{itemId}/review/interval":{"put":{"operationId":"reviews.setInterval","summary":"Set the review interval of an article","description":"Sets an interval of the article's own, switches reviews off for it, or returns to the knowledge base's.\n\nRequires the permission `item.edit` on the item in `itemId`.","tags":["Knowledge base reviews"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the article.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"intervalMonths":{"anyOf":[{"anyOf":[{"type":"number","const":0},{"anyOf":[{"type":"number","const":3},{"type":"number","const":6},{"type":"number","const":12}]}],"description":"Review interval in months."},{"type":"null"}],"description":"3, 6 or 12 months, 0 for no reviews, or null to use the interval of the knowledge base."}},"required":["intervalMonths"],"additionalProperties":false,"description":"The interval of the article."},"example":{"intervalMonths":12}}}},"responses":{"200":{"description":"The review state after the change.","content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"ID of the article."},"intervalMonths":{"anyOf":[{"anyOf":[{"type":"number","const":0},{"anyOf":[{"type":"number","const":3},{"type":"number","const":6},{"type":"number","const":12}]}],"description":"Review interval in months."},{"type":"null"}],"description":"Interval set on the article itself: 0 for no reviews, or null when it uses the knowledge base's."},"effectiveIntervalMonths":{"anyOf":[{"anyOf":[{"type":"number","const":3},{"type":"number","const":6},{"type":"number","const":12}],"description":"Review interval in months."},{"type":"null"}],"description":"Interval that applies, or null when none."},"inherited":{"type":"boolean","description":"Whether the interval comes from the knowledge base."},"publishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the article was first published, or null. ISO 8601 timestamp in UTC."},"reviewedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the article was last marked as reviewed, or null. ISO 8601 timestamp in UTC."},"reviewedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the person."},"name":{"description":"Name of the person, or null when the caller may not see the person.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null without one. Changes whenever the picture changes; load the picture from `GET /api/v1/accounts/{accountId}/picture`.","type":["string","null"]}},"required":["id","name","pictureRef"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who reviewed it last, or null."},"dueAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the next review is due, or null when no interval applies. ISO 8601 timestamp in UTC."},"sourceChangedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When a source page changed after the last review, or null. ISO 8601 timestamp in UTC."},"state":{"type":"string","enum":["overdue","sourceChanged","dueSoon","current","off"],"description":"`overdue`: the interval has passed. `sourceChanged`: a source page changed since the last review. `dueSoon`: due within 30 days. `current`: reviewed within the interval. `off`: no interval applies."}},"required":["itemId","intervalMonths","effectiveIntervalMonths","inherited","publishedAt","reviewedAt","reviewedBy","dueAt","sourceChangedAt","state"],"additionalProperties":false,"description":"Review state of an article."},"example":{"itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a50","intervalMonths":null,"effectiveIntervalMonths":6,"inherited":true,"publishedAt":"2026-03-02T09:00:00.000Z","reviewedAt":"2026-10-02T09:00:00.000Z","reviewedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Weber","pictureRef":null},"dueAt":"2027-04-02T09:00:00.000Z","sourceChangedAt":null,"state":"current"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notArticle`: The item is not an article of a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notArticle":{"value":{"type":"urn:lunedo:problem:notArticle","title":"The item is not an article of a knowledge base","status":409,"code":"notArticle"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/articles/{itemId}/reviews":{"post":{"operationId":"reviews.markReviewed","summary":"Mark an article as reviewed","description":"Records who reviewed the article and when, without a new version. The next due date starts from now and changed source pages count as seen. Audited.\n\nRequires the permission `item.edit` on the item in `itemId`.","tags":["Knowledge base reviews"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the article.","schema":{"type":"string","format":"uuid"}}],"responses":{"201":{"description":"The recorded review.","content":{"application/json":{"schema":{"type":"object","properties":{"reviewId":{"type":"string","format":"uuid","description":"ID of the review, used to undo it."},"reviewedAt":{"type":"string","format":"date-time","description":"When it was recorded. ISO 8601 timestamp in UTC."},"dueAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the next review is due, or null. ISO 8601 timestamp in UTC."}},"required":["reviewId","reviewedAt","dueAt"],"additionalProperties":false,"description":"The recorded review."},"example":{"reviewId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a80","reviewedAt":"2026-10-18T09:00:00.000Z","dueAt":"2027-04-18T09:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`articleNotPublished`: The article is not published yet. `notArticle`: The item is not an article of a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"articleNotPublished":{"value":{"type":"urn:lunedo:problem:articleNotPublished","title":"The article is not published yet","status":409,"code":"articleNotPublished"}},"notArticle":{"value":{"type":"urn:lunedo:problem:notArticle","title":"The item is not an article of a knowledge base","status":409,"code":"notArticle"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/articles/{itemId}/reviews/{reviewId}":{"delete":{"operationId":"reviews.undo","summary":"Undo a review","description":"Restores the state before the latest review. Only the person who recorded it can undo it, within two minutes. Audited.\n\nRequires the permission `item.edit` on the item in `itemId`.","tags":["Knowledge base reviews"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the article.","schema":{"type":"string","format":"uuid"}},{"name":"reviewId","in":"path","required":true,"description":"ID of the review.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notArticle`: The item is not an article of a knowledge base. `reviewNotUndoable`: The review can no longer be undone.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notArticle":{"value":{"type":"urn:lunedo:problem:notArticle","title":"The item is not an article of a knowledge base","status":409,"code":"notArticle"}},"reviewNotUndoable":{"value":{"type":"urn:lunedo:problem:reviewNotUndoable","title":"The review can no longer be undone","status":409,"code":"reviewNotUndoable"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/articles/{itemId}/sources":{"get":{"operationId":"reviews.sources","summary":"List the source pages of an article","description":"Lists the internal pages the article is based on. Pages the caller cannot read are left out. Source pages never appear in what readers of a knowledge base see.\n\nRequires the permission `item.view` on the item in `itemId`.","tags":["Knowledge base reviews"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the article.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The source pages.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the source page."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the source page in the addresses of the app."},"title":{"type":"string","description":"Title of the source page."},"spaceKey":{"type":"string","description":"Key of the space of the source page."},"spaceName":{"type":"string","description":"Name of the space of the source page."},"changedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the page changed after the last review of the article, or null. ISO 8601 timestamp in UTC."}},"required":["id","number","title","spaceKey","spaceName","changedAt"],"additionalProperties":false,"description":"An internal page the article is based on."},"description":"Source pages the caller can read. Others are left out, as if they were not linked."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","number":1041,"title":"VPN gateway","spaceKey":"OPS","spaceName":"IT operations","changedAt":null}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"reviews.addSource","summary":"Link a source page to an article","description":"Links an internal page. When it is published with changes, the article's owner is reminded to review it. At most 20 per article. Audited.\n\nRequires the permission `item.edit` on the item in `itemId`.","tags":["Knowledge base reviews"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the article.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sourceId":{"type":"string","format":"uuid","description":"ID of a page the caller can read, in a space that is not a knowledge base."}},"required":["sourceId"],"additionalProperties":false,"description":"The source page to link."},"example":{"sourceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70"}}}},"responses":{"200":{"description":"The source pages after the change.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the source page."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the source page in the addresses of the app."},"title":{"type":"string","description":"Title of the source page."},"spaceKey":{"type":"string","description":"Key of the space of the source page."},"spaceName":{"type":"string","description":"Name of the space of the source page."},"changedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the page changed after the last review of the article, or null. ISO 8601 timestamp in UTC."}},"required":["id","number","title","spaceKey","spaceName","changedAt"],"additionalProperties":false,"description":"An internal page the article is based on."},"description":"Source pages the caller can read. Others are left out, as if they were not linked."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","number":1041,"title":"VPN gateway","spaceKey":"OPS","spaceName":"IT operations","changedAt":null}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidSourcePage`: The page cannot be a source.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidSourcePage":{"value":{"type":"urn:lunedo:problem:invalidSourcePage","title":"The page cannot be a source","status":400,"code":"invalidSourcePage"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `sourceNotFound`: The source page does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"sourceNotFound":{"value":{"type":"urn:lunedo:problem:sourceNotFound","title":"The source page does not exist","status":404,"code":"sourceNotFound"}}}}}},"409":{"description":"`notArticle`: The item is not an article of a knowledge base. `tooManySources`: The article has too many source pages.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notArticle":{"value":{"type":"urn:lunedo:problem:notArticle","title":"The item is not an article of a knowledge base","status":409,"code":"notArticle"}},"tooManySources":{"value":{"type":"urn:lunedo:problem:tooManySources","title":"The article has too many source pages","status":409,"code":"tooManySources"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/articles/{itemId}/sources/{sourceId}":{"delete":{"operationId":"reviews.removeSource","summary":"Remove a source page from an article","description":"Removes the link to a source page the caller can read. Audited.\n\nRequires the permission `item.edit` on the item in `itemId`.","tags":["Knowledge base reviews"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the article.","schema":{"type":"string","format":"uuid"}},{"name":"sourceId","in":"path","required":true,"description":"ID of the source page.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The source pages after the change.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the source page."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the source page in the addresses of the app."},"title":{"type":"string","description":"Title of the source page."},"spaceKey":{"type":"string","description":"Key of the space of the source page."},"spaceName":{"type":"string","description":"Name of the space of the source page."},"changedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the page changed after the last review of the article, or null. ISO 8601 timestamp in UTC."}},"required":["id","number","title","spaceKey","spaceName","changedAt"],"additionalProperties":false,"description":"An internal page the article is based on."},"description":"Source pages the caller can read. Others are left out, as if they were not linked."},"example":[]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `sourceNotFound`: The source page does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"sourceNotFound":{"value":{"type":"urn:lunedo:problem:sourceNotFound","title":"The source page does not exist","status":404,"code":"sourceNotFound"}}}}}},"409":{"description":"`notArticle`: The item is not an article of a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notArticle":{"value":{"type":"urn:lunedo:problem:notArticle","title":"The item is not an article of a knowledge base","status":409,"code":"notArticle"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/articles/{itemId}/translations":{"get":{"operationId":"knowledgeBases.translations","summary":"List the translations of an article","description":"Returns the original article and one entry per enabled language, with the state of each translation. Translations the caller cannot read are listed as missing.\n\nRequires the permission `item.view` on the item in `itemId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the article.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The translations.","content":{"application/json":{"schema":{"type":"object","properties":{"sourceId":{"type":"string","format":"uuid","description":"ID of the original article."},"spaceId":{"type":"string","format":"uuid","description":"ID of the knowledge base."},"defaultLanguage":{"type":"string","description":"Language as a two-letter code such as `de` or `en`."},"language":{"type":"string","description":"Language of the article that was asked for."},"translations":{"type":"array","items":{"type":"object","properties":{"language":{"type":"string","description":"Language as a two-letter code such as `de` or `en`."},"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the article in this language, or null."},"itemNumber":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the article in this language in the addresses of the app, or null."},"title":{"description":"Title in this language, or null.","type":["string","null"]},"state":{"type":"string","enum":["original","current","outdated","unpublished","missing"],"description":"`original`: the article in the default language. `current`: published after its original. `outdated`: the original was published after it. `unpublished`: never published. `missing`: no translation yet."},"enabled":{"type":"boolean","description":"Whether the language is enabled; translations of other languages are not shown to readers."}},"required":["language","itemId","itemNumber","title","state","enabled"],"additionalProperties":false,"description":"The article in one language."},"description":"The original first, then one entry per language."}},"required":["sourceId","spaceId","defaultLanguage","language","translations"],"additionalProperties":false,"description":"An article with its translations."},"example":{"sourceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a61","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","defaultLanguage":"de","language":"de","translations":[{"language":"de","itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a61","itemNumber":123,"title":"VPN einrichten","state":"original","enabled":true},{"language":"en","itemId":null,"itemNumber":null,"title":null,"state":"missing","enabled":true}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"knowledgeBases.addTranslation","summary":"Add a translation of an article","description":"Creates the translation as a new article below the original, in the same category, with a copy of the original's content to translate. It shares the number of the original and gets its own address from its title.\n\nRequires the permission `item.edit` on the item in `itemId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the article.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"language":{"type":"string","description":"Language as a two-letter code such as `de` or `en`."}},"required":["language"],"additionalProperties":false,"description":"Language of the new translation."},"example":{"language":"en"}}}},"responses":{"201":{"description":"The new translation.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the item."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app, unique in the instance. It never changes and is never reused."},"spaceId":{"type":"string","format":"uuid","description":"Space of the item."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Parent item, or null at the root of the tree."},"kind":{"type":"string","description":"`page`, `folder`, `link`, `blogPost`, `meetingSeries`, `meetingTopic` or `whiteboard`. Blog posts and topics are not part of the tree; they appear in the blog and the meetings of their space. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title. Empty for a link to content the caller cannot read."},"description":{"type":"string","description":"Short description of a folder."},"width":{"type":"string","enum":["fixed","full"],"description":"Page width: `fixed` or `full`."},"numberHeadings":{"type":"boolean","description":"Whether the headings of the page are numbered in the page, in print and in Word."},"mode":{"type":"string","enum":["publish","live"],"description":"Editing mode of a page: `publish` (readers see the last published version while editors work on a draft) or `live` (readers see every change at once). Folders and links are always `live`."},"published":{"type":"boolean","description":"Whether readers can see the page. False for a page in publish mode that was never published; only editors see it."},"archived":{"type":"boolean","description":"Whether the item is archived. Archived items are read-only."},"position":{"type":"string","description":"Sort key among the siblings. Items sort by it in binary order."},"hasChildren":{"type":"boolean","description":"Whether the item has children."},"viewRestriction":{"type":"string","enum":["none","own","inherited"],"description":"Whether only an access list may view the item: set on the item itself, on a page above, or not at all."},"editRestricted":{"type":"boolean","description":"Whether only an access list may edit the item."},"link":{"anyOf":[{"type":"object","properties":{"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Linked page, folder or whiteboard, or null for an address or when the caller cannot read it."},"url":{"description":"Linked `http` or `https` address, or null.","type":["string","null"]},"accessible":{"type":"boolean","description":"Whether the caller can open the target. If not, the title is empty."},"inTrash":{"type":"boolean","description":"Whether the target is in the trash. Only true for callers who could read it before."},"target":{"anyOf":[{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"Space of the target."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the target in the addresses of the app."},"spaceKey":{"type":"string","description":"Key of that space."},"kind":{"type":"string","description":"Kind of the target. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title of the target."}},"required":["spaceId","number","spaceKey","kind","title"],"additionalProperties":false},{"type":"null"}],"description":"The linked page, folder or whiteboard, or null."}},"required":["itemId","url","accessible","inTrash","target"],"additionalProperties":false,"description":"Where a link in the page tree points."},{"type":"null"}],"description":"Target of a link, or null for pages and folders."},"creatorId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Account that created the item, or null."},"contentLanguage":{"anyOf":[{"type":"string","description":"Content language as an ISO 639-1 code, or `other` for a language without its own word matching. Words are then matched as written. New values can be added in later versions; handle unknown values.","x-extensible-enum":["ar","ca","da","de","el","en","es","eu","fi","fr","ga","hi","hu","hy","id","it","lt","nb","ne","nl","pt","ro","ru","sr","sv","ta","tr","yi","other"]},{"type":"null"}],"description":"Language of the page content for search, or null to use the language of the space."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Type of an article in a knowledge base, or null for other items and articles without a type."},"translationOf":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Original article of a translation in a knowledge base, or null. A translation is listed below its original; `contentLanguage` is its language."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of the item, or null. The owner stays set when the person leaves; `owner.active` in the item details says whether the item has an active owner."},"status":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the status value."},"builtIn":{"anyOf":[{"type":"string","x-extensible-enum":["roughDraft","inProgress","readyForReview","verified"]},{"type":"null"}],"description":"Which default value this is, or null for a value a space admin added. Clients show the translated name of a default value unless `name` is set. New values can be added in later versions; handle unknown values."},"name":{"description":"Name set by a space admin, or null to show the default name.","type":["string","null"]},"color":{"type":"string","enum":["neutral","accent","info","success","warning","danger"],"description":"Color of the status: `neutral`, `accent`, `info`, `success`, `warning` or `danger`."}},"required":["id","builtIn","name","color"],"additionalProperties":false,"description":"A page status."},{"type":"null"}],"description":"Status of a page, or null when it has none or page status is turned off in the space."},"createdAt":{"type":"string","format":"date-time","description":"When the item was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the item last changed in the tree. ISO 8601 timestamp in UTC."},"contentUpdatedAt":{"type":"string","format":"date-time","description":"When the content of the page last changed. ISO 8601 timestamp in UTC."}},"required":["id","number","spaceId","parentId","kind","title","description","width","numberHeadings","mode","published","archived","position","hasChildren","viewRestriction","editRestricted","link","creatorId","contentLanguage","articleType","translationOf","ownerId","status","createdAt","updatedAt","contentUpdatedAt"],"additionalProperties":false,"description":"An item of the page tree."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","parentId":null,"kind":"page","title":"VPN access for remote staff","description":"","width":"fixed","numberHeadings":false,"mode":"publish","published":true,"archived":false,"position":"a1","hasChildren":false,"viewRestriction":"none","editRestricted":false,"link":null,"creatorId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","ownerId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","contentLanguage":null,"articleType":null,"translationOf":null,"status":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","builtIn":"verified","name":null,"color":"success"},"createdAt":"2026-10-05T08:00:00.000Z","updatedAt":"2026-10-05T08:00:00.000Z","contentUpdatedAt":"2026-10-05T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidLanguage`: The language is not supported.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidLanguage":{"value":{"type":"urn:lunedo:problem:invalidLanguage","title":"The language is not supported","status":400,"code":"invalidLanguage"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`languageNotEnabled`: The language is not enabled for the knowledge base. `translationExists`: The article already has a translation into this language. `translationSource`: Only original articles can be translated.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"languageNotEnabled":{"value":{"type":"urn:lunedo:problem:languageNotEnabled","title":"The language is not enabled for the knowledge base","status":409,"code":"languageNotEnabled"}},"translationExists":{"value":{"type":"urn:lunedo:problem:translationExists","title":"The article already has a translation into this language","status":409,"code":"translationExists"}},"translationSource":{"value":{"type":"urn:lunedo:problem:translationSource","title":"Only original articles can be translated","status":409,"code":"translationSource"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/articles/{itemId}/type":{"put":{"operationId":"knowledgeBases.setType","summary":"Change the type of an article","description":"Sets the type that readers can filter by, or removes it.\n\nRequires the permission `item.edit` on the item in `itemId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the article.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"The new type, or null for none."}},"required":["type"],"additionalProperties":false,"description":"The article type."},"example":{"type":"troubleshooting"}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidArticleType`: Only articles have an article type. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidArticleType":{"value":{"type":"urn:lunedo:problem:invalidArticleType","title":"Only articles have an article type","status":400,"code":"invalidArticleType"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/attachments/{attachmentId}":{"delete":{"operationId":"attachments.delete","summary":"Delete an attachment","description":"Removes the attachment from the page. It can be brought back with all versions until the page itself is deleted for good. A blog post that used it as cover loses its cover.\n\nRequires the permission `attachment.edit` on the attachment in `attachmentId`.","tags":["Attachments"],"x-lunedo-permission":{"action":"attachment.edit","resource":"attachment","parameter":"attachmentId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"attachmentId","in":"path","required":true,"description":"ID of the attachment.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"get":{"operationId":"attachments.get","summary":"Get an attachment","description":"Returns the attachment with its current version: the draft state for people who can edit the page, the published state for everyone else.\n\nRequires the permission `attachment.view` on the attachment in `attachmentId`.","tags":["Attachments"],"x-lunedo-permission":{"action":"attachment.view","resource":"attachment","parameter":"attachmentId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"attachmentId","in":"path","required":true,"description":"ID of the attachment.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The attachment.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the attachment."},"itemId":{"type":"string","format":"uuid","description":"Page or blog post the file is attached to."},"name":{"type":"string","description":"File name of the current version."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the current version in bytes."},"contentType":{"type":"string","description":"Media type, decided from the content of the file."},"preview":{"type":"string","description":"How the file can be previewed; `none` offers only the download. New values can be added in later versions; handle unknown values.","x-extensible-enum":["image","pdf","video","audio","text","code","markdown","csv","svg","word","excel","none"]},"inline":{"type":"boolean","description":"Whether browsers may show the file directly: images, video and audio."},"tooLargeForPreview":{"type":"boolean","description":"Whether the image has more than 100 megapixels. Such images get no smaller version; pages and previews show them as a file that opens in full size."},"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the current version."},"versions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of stored versions."},"draft":{"anyOf":[{"type":"string","x-extensible-enum":["added","changed","deleted"]},{"type":"null"}],"description":"Only for people who can edit the page: `added` when readers do not see the file until the next publication, `changed` when readers still see an earlier version, `deleted` when the file was deleted in the draft and readers still see it until the next publication; restore it to keep it. Null when readers see this version. New values can be added in later versions; handle unknown values."},"uploadedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who uploaded the current version."},"uploadedAt":{"type":"string","format":"date-time","description":"When the current version was uploaded. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the file was first attached. ISO 8601 timestamp in UTC."}},"required":["id","itemId","name","size","contentType","preview","inline","tooLargeForPreview","version","versions","draft","uploadedBy","uploadedAt","createdAt"],"additionalProperties":false,"description":"A file attached to a page or blog post."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","name":"network-diagram.png","size":48213,"contentType":"image/png","preview":"image","inline":true,"tooLargeForPreview":false,"version":2,"versions":2,"draft":null,"uploadedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"uploadedAt":"2026-10-01T09:30:00.000Z","createdAt":"2026-09-28T14:02:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/attachments/{attachmentId}/content":{"get":{"operationId":"attachments.content","summary":"Download an attachment","description":"Sends the bytes of the current or a given version. People who cannot edit the page get the published version and can ask only for published versions. Images, video and audio are sent inline unless `download` is set; every other type always as a download.\n\nRequires the permission `attachment.view` on the attachment in `attachmentId`.","tags":["Attachments"],"x-lunedo-permission":{"action":"attachment.view","resource":"attachment","parameter":"attachmentId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"attachmentId","in":"path","required":true,"description":"ID of the attachment.","schema":{"type":"string","format":"uuid"}},{"name":"version","in":"query","required":false,"description":"Number of the version. Default: the current one.","schema":{"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"download","in":"query","required":false,"description":"`true` always sends the file as a download. Otherwise images, video and audio are sent inline and everything else as a download.","schema":{"default":"false","type":"string","enum":["true","false"]}},{"name":"size","in":"query","required":false,"description":"Size of an image. `display` sends a version whose longest edge is at most 2048 pixels, `preview` one of at most 400 pixels, both as WebP without metadata. The original is sent while no such version exists, for images that are already small enough, and for every other type. Images above 100 megapixels get no smaller version and answer `imageTooLarge`.","schema":{"default":"original","type":"string","enum":["original","display","preview"]}}],"responses":{"200":{"description":"The file. The content type is decided from the content. Files are sent with `Content-Security-Policy: sandbox` and `X-Content-Type-Options: nosniff`; ranges are supported.","content":{"*/*":{"schema":{"type":"string"},"example":""}}},"206":{"description":"Part of the file, for a request with a `Range` header.","content":{"*/*":{"schema":{"type":"string"},"example":""}}},"304":{"description":"Not modified: the file matches the `If-None-Match` header."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `versionNotFound`: The version does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"versionNotFound":{"value":{"type":"urn:lunedo:problem:versionNotFound","title":"The version does not exist","status":404,"code":"versionNotFound"}}}}}},"409":{"description":"`imageTooLarge`: The image is too large for a smaller version.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"imageTooLarge":{"value":{"type":"urn:lunedo:problem:imageTooLarge","title":"The image is too large for a smaller version","status":409,"code":"imageTooLarge"}}}}}},"416":{"description":"`rangeNotSatisfiable`: The requested range is not available.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rangeNotSatisfiable":{"value":{"type":"urn:lunedo:problem:rangeNotSatisfiable","title":"The requested range is not available","status":416,"code":"rangeNotSatisfiable"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/attachments/{attachmentId}/link":{"get":{"operationId":"attachments.link","summary":"Get a short-lived address of an attachment","description":"Returns an address of the file that works for 10 minutes without the session cookie, for media players and the separate file origin. Access is checked again on every request to it.\n\nRequires the permission `attachment.view` on the attachment in `attachmentId`. Needs a signed-in session; API tokens are refused.","tags":["Attachments"],"x-lunedo-permission":{"action":"attachment.view","resource":"attachment","parameter":"attachmentId"},"security":[{"sessionCookie":[]}],"parameters":[{"name":"attachmentId","in":"path","required":true,"description":"ID of the attachment.","schema":{"type":"string","format":"uuid"}},{"name":"version","in":"query","required":false,"description":"Number of the version. Default: the current one.","schema":{"type":"integer","minimum":1,"maximum":9007199254740991}}],"responses":{"200":{"description":"The address.","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"Address of the file. It starts with the file origin when one is configured."},"expiresAt":{"type":"string","format":"date-time","description":"When the address stops working. ISO 8601 timestamp in UTC."}},"required":["url","expiresAt"],"additionalProperties":false,"description":"A short-lived address of a file."},"example":{"url":"/api/v1/files/1a2b3c.example","expiresAt":"2026-10-08T12:10:00.000Z"}}}},"400":{"description":"`invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}}}}},"/api/v1/attachments/{attachmentId}/versions":{"get":{"operationId":"attachments.versions","summary":"List the versions of an attachment","description":"Lists the stored versions, newest first. People who cannot edit the page see only versions that were published. When a new version is added and more versions than configured exist, the oldest version not marked to keep is removed.\n\nRequires the permission `attachment.view` on the attachment in `attachmentId`.","tags":["Attachments"],"x-lunedo-permission":{"action":"attachment.view","resource":"attachment","parameter":"attachmentId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"attachmentId","in":"path","required":true,"description":"ID of the attachment.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The versions.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the version."},"number":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the version, starting at 1."},"name":{"type":"string","description":"File name when this version was uploaded."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size in bytes."},"contentType":{"type":"string","description":"Media type, decided from the content."},"restoredFrom":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Version this one restored, or null for an upload."},"kept":{"type":"boolean","description":"Whether the version is marked to keep. Marked versions are never removed automatically and do not count towards the number of versions kept."},"uploadedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who uploaded or restored it."},"uploadedAt":{"type":"string","format":"date-time","description":"When it was stored. ISO 8601 timestamp in UTC."}},"required":["id","number","name","size","contentType","restoredFrom","kept","uploadedBy","uploadedAt"],"additionalProperties":false,"description":"A version of an attachment."},"description":"Versions, newest first."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a41","number":2,"name":"network-diagram.png","size":48213,"contentType":"image/png","restoredFrom":null,"kept":false,"uploadedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"uploadedAt":"2026-10-01T09:30:00.000Z"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/attachments/{attachmentId}/versions/{number}/keep":{"put":{"operationId":"attachments.keepVersion","summary":"Keep a version","description":"Marks a version to keep or removes the mark. Marked versions are never removed automatically and do not count towards the number of versions kept. The change is recorded in the audit log.\n\nRequires the permission `attachment.edit` on the attachment in `attachmentId`.","tags":["Attachments"],"x-lunedo-permission":{"action":"attachment.edit","resource":"attachment","parameter":"attachmentId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"attachmentId","in":"path","required":true,"description":"ID of the attachment.","schema":{"type":"string","format":"uuid"}},{"name":"number","in":"path","required":true,"description":"Number of the version, starting at 1.","schema":{"type":"integer","minimum":1,"maximum":9007199254740991}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kept":{"type":"boolean","description":"True to keep the version, false to let it be removed again."}},"required":["kept"],"additionalProperties":false,"description":"Whether to keep a version."},"example":{"kept":true}}}},"responses":{"200":{"description":"The version.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the version."},"number":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the version, starting at 1."},"name":{"type":"string","description":"File name when this version was uploaded."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size in bytes."},"contentType":{"type":"string","description":"Media type, decided from the content."},"restoredFrom":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Version this one restored, or null for an upload."},"kept":{"type":"boolean","description":"Whether the version is marked to keep. Marked versions are never removed automatically and do not count towards the number of versions kept."},"uploadedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who uploaded or restored it."},"uploadedAt":{"type":"string","format":"date-time","description":"When it was stored. ISO 8601 timestamp in UTC."}},"required":["id","number","name","size","contentType","restoredFrom","kept","uploadedBy","uploadedAt"],"additionalProperties":false,"description":"A version of an attachment."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a41","number":2,"name":"network-diagram.png","size":48213,"contentType":"image/png","restoredFrom":null,"kept":true,"uploadedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"uploadedAt":"2026-10-01T09:30:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `versionNotFound`: The version does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"versionNotFound":{"value":{"type":"urn:lunedo:problem:versionNotFound","title":"The version does not exist","status":404,"code":"versionNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/attachments/{attachmentId}/versions/{number}/restore":{"post":{"operationId":"attachments.restoreVersion","summary":"Restore an earlier version","description":"Makes an earlier version current again by adding it as a new version.\n\nRequires the permission `attachment.edit` on the attachment in `attachmentId`.","tags":["Attachments"],"x-lunedo-permission":{"action":"attachment.edit","resource":"attachment","parameter":"attachmentId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"attachmentId","in":"path","required":true,"description":"ID of the attachment.","schema":{"type":"string","format":"uuid"}},{"name":"number","in":"path","required":true,"description":"Number of the version, starting at 1.","schema":{"type":"integer","minimum":1,"maximum":9007199254740991}}],"responses":{"200":{"description":"The attachment.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the attachment."},"itemId":{"type":"string","format":"uuid","description":"Page or blog post the file is attached to."},"name":{"type":"string","description":"File name of the current version."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the current version in bytes."},"contentType":{"type":"string","description":"Media type, decided from the content of the file."},"preview":{"type":"string","description":"How the file can be previewed; `none` offers only the download. New values can be added in later versions; handle unknown values.","x-extensible-enum":["image","pdf","video","audio","text","code","markdown","csv","svg","word","excel","none"]},"inline":{"type":"boolean","description":"Whether browsers may show the file directly: images, video and audio."},"tooLargeForPreview":{"type":"boolean","description":"Whether the image has more than 100 megapixels. Such images get no smaller version; pages and previews show them as a file that opens in full size."},"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the current version."},"versions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of stored versions."},"draft":{"anyOf":[{"type":"string","x-extensible-enum":["added","changed","deleted"]},{"type":"null"}],"description":"Only for people who can edit the page: `added` when readers do not see the file until the next publication, `changed` when readers still see an earlier version, `deleted` when the file was deleted in the draft and readers still see it until the next publication; restore it to keep it. Null when readers see this version. New values can be added in later versions; handle unknown values."},"uploadedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who uploaded the current version."},"uploadedAt":{"type":"string","format":"date-time","description":"When the current version was uploaded. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the file was first attached. ISO 8601 timestamp in UTC."}},"required":["id","itemId","name","size","contentType","preview","inline","tooLargeForPreview","version","versions","draft","uploadedBy","uploadedAt","createdAt"],"additionalProperties":false,"description":"A file attached to a page or blog post."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","name":"network-diagram.png","size":48213,"contentType":"image/png","preview":"image","inline":true,"tooLargeForPreview":false,"version":2,"versions":2,"draft":null,"uploadedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"uploadedAt":"2026-10-01T09:30:00.000Z","createdAt":"2026-09-28T14:02:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `versionNotFound`: The version does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"versionNotFound":{"value":{"type":"urn:lunedo:problem:versionNotFound","title":"The version does not exist","status":404,"code":"versionNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/blog-posts/{postId}":{"get":{"operationId":"blog.get","summary":"Get a blog post","description":"Returns the details of a blog post. Its content comes from the page content endpoints.\n\nRequires the permission `item.view` on the item in `postId`.","tags":["Blog"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"postId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"postId","in":"path","required":true,"description":"ID of the blog post.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The post.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the blog post in the addresses of the app."},"spaceId":{"type":"string","format":"uuid","description":"Space of the post."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."},"title":{"type":"string","description":"Title as readers see it."},"excerpt":{"type":"string","description":"Short summary shown in lists."},"labels":{"type":"array","items":{"type":"string","description":"A label."},"description":"Labels, sorted."},"author":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who wrote the post, or null."},"published":{"type":"boolean","description":"Whether the post was published. Unpublished posts are visible only to editors."},"publishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post was first published, or null. ISO 8601 timestamp in UTC."},"scheduledAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post will be published, or null. ISO 8601 timestamp in UTC."},"scheduledTimeZone":{"description":"Time zone the author scheduled it in, or null.","type":["string","null"]},"scheduledBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who scheduled the publication, or null."},"held":{"type":"boolean","description":"Whether the scheduled publication is waiting for a space admin because the person who scheduled it can no longer edit the post."},"pinnedInSpace":{"type":"boolean","description":"Whether the post is pinned at the top of its space's blog."},"pinnedInOrganization":{"type":"boolean","description":"Whether the post is pinned in the organization's blog overview."},"cover":{"anyOf":[{"type":"object","properties":{"attachmentId":{"type":"string","format":"uuid","description":"The image attachment."},"focusX":{"type":"number","description":"Horizontal focal point from 0 (left) to 1 (right)."},"focusY":{"type":"number","description":"Vertical focal point from 0 (top) to 1 (bottom)."}},"required":["attachmentId","focusX","focusY"],"additionalProperties":false},{"type":"null"}],"description":"Cover image with the point that stays visible in every crop, or null."},"commentCount":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Number of comments and replies on the post that are not deleted."},"createdAt":{"type":"string","format":"date-time","description":"When the post was created. ISO 8601 timestamp in UTC."}},"required":["id","number","spaceId","spaceKey","spaceName","title","excerpt","labels","author","published","publishedAt","scheduledAt","scheduledTimeZone","scheduledBy","held","pinnedInSpace","pinnedInOrganization","cover","commentCount","createdAt"],"additionalProperties":false,"description":"A blog post."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5d01","number":1077,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","title":"New VPN client from Monday","excerpt":"The company portal ships WireGuard 0.6 on Monday.","labels":["vpn"],"author":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"published":true,"publishedAt":"2026-10-06T07:00:00.000Z","scheduledAt":null,"scheduledTimeZone":null,"scheduledBy":null,"held":false,"pinnedInSpace":false,"pinnedInOrganization":true,"cover":{"attachmentId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","focusX":0.5,"focusY":0.3},"commentCount":4,"createdAt":"2026-10-05T15:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"patch":{"operationId":"blog.update","summary":"Change a blog post","description":"Changes the excerpt. The title is changed through the item endpoint and becomes visible with the next publication.\n\nRequires the permission `item.edit` on the item in `postId`.","tags":["Blog"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"postId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"postId","in":"path","required":true,"description":"ID of the blog post.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"excerpt":{"description":"Summary, up to 500 characters.","type":"string","maxLength":500}},"additionalProperties":false,"description":"Changes to a blog post. Change the title through the item endpoint."},"example":{"excerpt":"Existing tunnels keep working."}}}},"responses":{"200":{"description":"The changed post.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the blog post in the addresses of the app."},"spaceId":{"type":"string","format":"uuid","description":"Space of the post."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."},"title":{"type":"string","description":"Title as readers see it."},"excerpt":{"type":"string","description":"Short summary shown in lists."},"labels":{"type":"array","items":{"type":"string","description":"A label."},"description":"Labels, sorted."},"author":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who wrote the post, or null."},"published":{"type":"boolean","description":"Whether the post was published. Unpublished posts are visible only to editors."},"publishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post was first published, or null. ISO 8601 timestamp in UTC."},"scheduledAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post will be published, or null. ISO 8601 timestamp in UTC."},"scheduledTimeZone":{"description":"Time zone the author scheduled it in, or null.","type":["string","null"]},"scheduledBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who scheduled the publication, or null."},"held":{"type":"boolean","description":"Whether the scheduled publication is waiting for a space admin because the person who scheduled it can no longer edit the post."},"pinnedInSpace":{"type":"boolean","description":"Whether the post is pinned at the top of its space's blog."},"pinnedInOrganization":{"type":"boolean","description":"Whether the post is pinned in the organization's blog overview."},"cover":{"anyOf":[{"type":"object","properties":{"attachmentId":{"type":"string","format":"uuid","description":"The image attachment."},"focusX":{"type":"number","description":"Horizontal focal point from 0 (left) to 1 (right)."},"focusY":{"type":"number","description":"Vertical focal point from 0 (top) to 1 (bottom)."}},"required":["attachmentId","focusX","focusY"],"additionalProperties":false},{"type":"null"}],"description":"Cover image with the point that stays visible in every crop, or null."},"commentCount":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Number of comments and replies on the post that are not deleted."},"createdAt":{"type":"string","format":"date-time","description":"When the post was created. ISO 8601 timestamp in UTC."}},"required":["id","number","spaceId","spaceKey","spaceName","title","excerpt","labels","author","published","publishedAt","scheduledAt","scheduledTimeZone","scheduledBy","held","pinnedInSpace","pinnedInOrganization","cover","commentCount","createdAt"],"additionalProperties":false,"description":"A blog post."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5d01","number":1077,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","title":"New VPN client from Monday","excerpt":"The company portal ships WireGuard 0.6 on Monday.","labels":["vpn"],"author":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"published":true,"publishedAt":"2026-10-06T07:00:00.000Z","scheduledAt":null,"scheduledTimeZone":null,"scheduledBy":null,"held":false,"pinnedInSpace":false,"pinnedInOrganization":true,"cover":{"attachmentId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","focusX":0.5,"focusY":0.3},"commentCount":4,"createdAt":"2026-10-05T15:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidExcerpt`: The excerpt is too long. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidExcerpt":{"value":{"type":"urn:lunedo:problem:invalidExcerpt","title":"The excerpt is too long","status":400,"code":"invalidExcerpt"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/blog-posts/{postId}/cover":{"put":{"operationId":"blog.cover","summary":"Set the cover image of a blog post","description":"Chooses an image attached to the post as cover, with the focal point that stays visible when lists crop the image. Send `attachmentId: null` to remove the cover.\n\nRequires the permission `item.edit` on the item in `postId`.","tags":["Blog"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"postId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"postId","in":"path","required":true,"description":"ID of the blog post.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"attachmentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"An image attached to the post, or null for no cover."},"focusX":{"default":0.5,"description":"Horizontal focal point from 0 (left) to 1 (right).","type":"number","minimum":0,"maximum":1},"focusY":{"default":0.5,"description":"Vertical focal point from 0 (top) to 1 (bottom).","type":"number","minimum":0,"maximum":1}},"required":["attachmentId"],"additionalProperties":false,"description":"The cover image."},"example":{"attachmentId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","focusX":0.5,"focusY":0.3}}}},"responses":{"200":{"description":"The post.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the blog post in the addresses of the app."},"spaceId":{"type":"string","format":"uuid","description":"Space of the post."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."},"title":{"type":"string","description":"Title as readers see it."},"excerpt":{"type":"string","description":"Short summary shown in lists."},"labels":{"type":"array","items":{"type":"string","description":"A label."},"description":"Labels, sorted."},"author":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who wrote the post, or null."},"published":{"type":"boolean","description":"Whether the post was published. Unpublished posts are visible only to editors."},"publishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post was first published, or null. ISO 8601 timestamp in UTC."},"scheduledAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post will be published, or null. ISO 8601 timestamp in UTC."},"scheduledTimeZone":{"description":"Time zone the author scheduled it in, or null.","type":["string","null"]},"scheduledBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who scheduled the publication, or null."},"held":{"type":"boolean","description":"Whether the scheduled publication is waiting for a space admin because the person who scheduled it can no longer edit the post."},"pinnedInSpace":{"type":"boolean","description":"Whether the post is pinned at the top of its space's blog."},"pinnedInOrganization":{"type":"boolean","description":"Whether the post is pinned in the organization's blog overview."},"cover":{"anyOf":[{"type":"object","properties":{"attachmentId":{"type":"string","format":"uuid","description":"The image attachment."},"focusX":{"type":"number","description":"Horizontal focal point from 0 (left) to 1 (right)."},"focusY":{"type":"number","description":"Vertical focal point from 0 (top) to 1 (bottom)."}},"required":["attachmentId","focusX","focusY"],"additionalProperties":false},{"type":"null"}],"description":"Cover image with the point that stays visible in every crop, or null."},"commentCount":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Number of comments and replies on the post that are not deleted."},"createdAt":{"type":"string","format":"date-time","description":"When the post was created. ISO 8601 timestamp in UTC."}},"required":["id","number","spaceId","spaceKey","spaceName","title","excerpt","labels","author","published","publishedAt","scheduledAt","scheduledTimeZone","scheduledBy","held","pinnedInSpace","pinnedInOrganization","cover","commentCount","createdAt"],"additionalProperties":false,"description":"A blog post."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5d01","number":1077,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","title":"New VPN client from Monday","excerpt":"The company portal ships WireGuard 0.6 on Monday.","labels":["vpn"],"author":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"published":true,"publishedAt":"2026-10-06T07:00:00.000Z","scheduledAt":null,"scheduledTimeZone":null,"scheduledBy":null,"held":false,"pinnedInSpace":false,"pinnedInOrganization":true,"cover":{"attachmentId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","focusX":0.5,"focusY":0.3},"commentCount":4,"createdAt":"2026-10-05T15:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidCover`: The cover must be an image attached to the post. `invalidFocus`: The focal point lies outside the image. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidCover":{"value":{"type":"urn:lunedo:problem:invalidCover","title":"The cover must be an image attached to the post","status":400,"code":"invalidCover"}},"invalidFocus":{"value":{"type":"urn:lunedo:problem:invalidFocus","title":"The focal point lies outside the image","status":400,"code":"invalidFocus"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/blog-posts/{postId}/held":{"delete":{"operationId":"blog.cancelHeld","summary":"Cancel the schedule of a held blog post","description":"Drops the schedule of a post that is waiting for approval. The post stays a draft. Recorded in the audit log.\n\nRequires the permission `item.approveSchedule` on the item in `postId`.","tags":["Blog"],"x-lunedo-permission":{"action":"item.approveSchedule","resource":"item","parameter":"postId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"postId","in":"path","required":true,"description":"ID of the blog post.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The post without schedule.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the blog post in the addresses of the app."},"spaceId":{"type":"string","format":"uuid","description":"Space of the post."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."},"title":{"type":"string","description":"Title as readers see it."},"excerpt":{"type":"string","description":"Short summary shown in lists."},"labels":{"type":"array","items":{"type":"string","description":"A label."},"description":"Labels, sorted."},"author":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who wrote the post, or null."},"published":{"type":"boolean","description":"Whether the post was published. Unpublished posts are visible only to editors."},"publishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post was first published, or null. ISO 8601 timestamp in UTC."},"scheduledAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post will be published, or null. ISO 8601 timestamp in UTC."},"scheduledTimeZone":{"description":"Time zone the author scheduled it in, or null.","type":["string","null"]},"scheduledBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who scheduled the publication, or null."},"held":{"type":"boolean","description":"Whether the scheduled publication is waiting for a space admin because the person who scheduled it can no longer edit the post."},"pinnedInSpace":{"type":"boolean","description":"Whether the post is pinned at the top of its space's blog."},"pinnedInOrganization":{"type":"boolean","description":"Whether the post is pinned in the organization's blog overview."},"cover":{"anyOf":[{"type":"object","properties":{"attachmentId":{"type":"string","format":"uuid","description":"The image attachment."},"focusX":{"type":"number","description":"Horizontal focal point from 0 (left) to 1 (right)."},"focusY":{"type":"number","description":"Vertical focal point from 0 (top) to 1 (bottom)."}},"required":["attachmentId","focusX","focusY"],"additionalProperties":false},{"type":"null"}],"description":"Cover image with the point that stays visible in every crop, or null."},"commentCount":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Number of comments and replies on the post that are not deleted."},"createdAt":{"type":"string","format":"date-time","description":"When the post was created. ISO 8601 timestamp in UTC."}},"required":["id","number","spaceId","spaceKey","spaceName","title","excerpt","labels","author","published","publishedAt","scheduledAt","scheduledTimeZone","scheduledBy","held","pinnedInSpace","pinnedInOrganization","cover","commentCount","createdAt"],"additionalProperties":false,"description":"A blog post."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5d01","number":1077,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","title":"New VPN client from Monday","excerpt":"The company portal ships WireGuard 0.6 on Monday.","labels":["vpn"],"author":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"published":false,"publishedAt":"2026-10-06T07:00:00.000Z","scheduledAt":null,"scheduledTimeZone":null,"scheduledBy":null,"held":false,"pinnedInSpace":false,"pinnedInOrganization":true,"cover":{"attachmentId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","focusX":0.5,"focusY":0.3},"commentCount":4,"createdAt":"2026-10-05T15:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notHeld`: The blog post is not waiting for approval.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notHeld":{"value":{"type":"urn:lunedo:problem:notHeld","title":"The blog post is not waiting for approval","status":409,"code":"notHeld"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/blog-posts/{postId}/held/publish":{"post":{"operationId":"blog.publishHeld","summary":"Publish a held blog post","description":"Publishes a scheduled post that is waiting for approval because the person who scheduled it can no longer edit it. Recorded in the audit log.\n\nRequires the permission `item.approveSchedule` on the item in `postId`.","tags":["Blog"],"x-lunedo-permission":{"action":"item.approveSchedule","resource":"item","parameter":"postId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"postId","in":"path","required":true,"description":"ID of the blog post.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The published post.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the blog post in the addresses of the app."},"spaceId":{"type":"string","format":"uuid","description":"Space of the post."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."},"title":{"type":"string","description":"Title as readers see it."},"excerpt":{"type":"string","description":"Short summary shown in lists."},"labels":{"type":"array","items":{"type":"string","description":"A label."},"description":"Labels, sorted."},"author":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who wrote the post, or null."},"published":{"type":"boolean","description":"Whether the post was published. Unpublished posts are visible only to editors."},"publishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post was first published, or null. ISO 8601 timestamp in UTC."},"scheduledAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post will be published, or null. ISO 8601 timestamp in UTC."},"scheduledTimeZone":{"description":"Time zone the author scheduled it in, or null.","type":["string","null"]},"scheduledBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who scheduled the publication, or null."},"held":{"type":"boolean","description":"Whether the scheduled publication is waiting for a space admin because the person who scheduled it can no longer edit the post."},"pinnedInSpace":{"type":"boolean","description":"Whether the post is pinned at the top of its space's blog."},"pinnedInOrganization":{"type":"boolean","description":"Whether the post is pinned in the organization's blog overview."},"cover":{"anyOf":[{"type":"object","properties":{"attachmentId":{"type":"string","format":"uuid","description":"The image attachment."},"focusX":{"type":"number","description":"Horizontal focal point from 0 (left) to 1 (right)."},"focusY":{"type":"number","description":"Vertical focal point from 0 (top) to 1 (bottom)."}},"required":["attachmentId","focusX","focusY"],"additionalProperties":false},{"type":"null"}],"description":"Cover image with the point that stays visible in every crop, or null."},"commentCount":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Number of comments and replies on the post that are not deleted."},"createdAt":{"type":"string","format":"date-time","description":"When the post was created. ISO 8601 timestamp in UTC."}},"required":["id","number","spaceId","spaceKey","spaceName","title","excerpt","labels","author","published","publishedAt","scheduledAt","scheduledTimeZone","scheduledBy","held","pinnedInSpace","pinnedInOrganization","cover","commentCount","createdAt"],"additionalProperties":false,"description":"A blog post."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5d01","number":1077,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","title":"New VPN client from Monday","excerpt":"The company portal ships WireGuard 0.6 on Monday.","labels":["vpn"],"author":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"published":true,"publishedAt":"2026-10-06T07:00:00.000Z","scheduledAt":null,"scheduledTimeZone":null,"scheduledBy":null,"held":false,"pinnedInSpace":false,"pinnedInOrganization":true,"cover":{"attachmentId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","focusX":0.5,"focusY":0.3},"commentCount":4,"createdAt":"2026-10-05T15:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notHeld`: The blog post is not waiting for approval.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notHeld":{"value":{"type":"urn:lunedo:problem:notHeld","title":"The blog post is not waiting for approval","status":409,"code":"notHeld"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/blog-posts/{postId}/pinned":{"put":{"operationId":"blog.pinInSpace","summary":"Pin a blog post in its space","description":"Space admins pin published posts at the top of their space's blog.\n\nRequires the permission `item.pin` on the item in `postId`.","tags":["Blog"],"x-lunedo-permission":{"action":"item.pin","resource":"item","parameter":"postId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"postId","in":"path","required":true,"description":"ID of the blog post.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"pinned":{"type":"boolean","description":"True to pin, false to unpin."}},"required":["pinned"],"additionalProperties":false,"description":"Pinned state."},"example":{"pinned":true}}}},"responses":{"200":{"description":"The post.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the blog post in the addresses of the app."},"spaceId":{"type":"string","format":"uuid","description":"Space of the post."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."},"title":{"type":"string","description":"Title as readers see it."},"excerpt":{"type":"string","description":"Short summary shown in lists."},"labels":{"type":"array","items":{"type":"string","description":"A label."},"description":"Labels, sorted."},"author":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who wrote the post, or null."},"published":{"type":"boolean","description":"Whether the post was published. Unpublished posts are visible only to editors."},"publishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post was first published, or null. ISO 8601 timestamp in UTC."},"scheduledAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post will be published, or null. ISO 8601 timestamp in UTC."},"scheduledTimeZone":{"description":"Time zone the author scheduled it in, or null.","type":["string","null"]},"scheduledBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who scheduled the publication, or null."},"held":{"type":"boolean","description":"Whether the scheduled publication is waiting for a space admin because the person who scheduled it can no longer edit the post."},"pinnedInSpace":{"type":"boolean","description":"Whether the post is pinned at the top of its space's blog."},"pinnedInOrganization":{"type":"boolean","description":"Whether the post is pinned in the organization's blog overview."},"cover":{"anyOf":[{"type":"object","properties":{"attachmentId":{"type":"string","format":"uuid","description":"The image attachment."},"focusX":{"type":"number","description":"Horizontal focal point from 0 (left) to 1 (right)."},"focusY":{"type":"number","description":"Vertical focal point from 0 (top) to 1 (bottom)."}},"required":["attachmentId","focusX","focusY"],"additionalProperties":false},{"type":"null"}],"description":"Cover image with the point that stays visible in every crop, or null."},"commentCount":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Number of comments and replies on the post that are not deleted."},"createdAt":{"type":"string","format":"date-time","description":"When the post was created. ISO 8601 timestamp in UTC."}},"required":["id","number","spaceId","spaceKey","spaceName","title","excerpt","labels","author","published","publishedAt","scheduledAt","scheduledTimeZone","scheduledBy","held","pinnedInSpace","pinnedInOrganization","cover","commentCount","createdAt"],"additionalProperties":false,"description":"A blog post."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5d01","number":1077,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","title":"New VPN client from Monday","excerpt":"The company portal ships WireGuard 0.6 on Monday.","labels":["vpn"],"author":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"published":true,"publishedAt":"2026-10-06T07:00:00.000Z","scheduledAt":null,"scheduledTimeZone":null,"scheduledBy":null,"held":false,"pinnedInSpace":true,"pinnedInOrganization":true,"cover":{"attachmentId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","focusX":0.5,"focusY":0.3},"commentCount":4,"createdAt":"2026-10-05T15:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notPublished`: The blog post is not published.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notPublished":{"value":{"type":"urn:lunedo:problem:notPublished","title":"The blog post is not published","status":409,"code":"notPublished"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/blog-posts/{postId}/schedule":{"delete":{"operationId":"blog.cancelSchedule","summary":"Cancel a scheduled publication","description":"Drops the schedule. The post stays a draft until someone publishes it.\n\nRequires the permission `item.edit` on the item in `postId`.","tags":["Blog"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"postId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"postId","in":"path","required":true,"description":"ID of the blog post.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The post without schedule.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the blog post in the addresses of the app."},"spaceId":{"type":"string","format":"uuid","description":"Space of the post."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."},"title":{"type":"string","description":"Title as readers see it."},"excerpt":{"type":"string","description":"Short summary shown in lists."},"labels":{"type":"array","items":{"type":"string","description":"A label."},"description":"Labels, sorted."},"author":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who wrote the post, or null."},"published":{"type":"boolean","description":"Whether the post was published. Unpublished posts are visible only to editors."},"publishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post was first published, or null. ISO 8601 timestamp in UTC."},"scheduledAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post will be published, or null. ISO 8601 timestamp in UTC."},"scheduledTimeZone":{"description":"Time zone the author scheduled it in, or null.","type":["string","null"]},"scheduledBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who scheduled the publication, or null."},"held":{"type":"boolean","description":"Whether the scheduled publication is waiting for a space admin because the person who scheduled it can no longer edit the post."},"pinnedInSpace":{"type":"boolean","description":"Whether the post is pinned at the top of its space's blog."},"pinnedInOrganization":{"type":"boolean","description":"Whether the post is pinned in the organization's blog overview."},"cover":{"anyOf":[{"type":"object","properties":{"attachmentId":{"type":"string","format":"uuid","description":"The image attachment."},"focusX":{"type":"number","description":"Horizontal focal point from 0 (left) to 1 (right)."},"focusY":{"type":"number","description":"Vertical focal point from 0 (top) to 1 (bottom)."}},"required":["attachmentId","focusX","focusY"],"additionalProperties":false},{"type":"null"}],"description":"Cover image with the point that stays visible in every crop, or null."},"commentCount":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Number of comments and replies on the post that are not deleted."},"createdAt":{"type":"string","format":"date-time","description":"When the post was created. ISO 8601 timestamp in UTC."}},"required":["id","number","spaceId","spaceKey","spaceName","title","excerpt","labels","author","published","publishedAt","scheduledAt","scheduledTimeZone","scheduledBy","held","pinnedInSpace","pinnedInOrganization","cover","commentCount","createdAt"],"additionalProperties":false,"description":"A blog post."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5d01","number":1077,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","title":"New VPN client from Monday","excerpt":"The company portal ships WireGuard 0.6 on Monday.","labels":["vpn"],"author":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"published":true,"publishedAt":"2026-10-06T07:00:00.000Z","scheduledAt":null,"scheduledTimeZone":null,"scheduledBy":null,"held":false,"pinnedInSpace":false,"pinnedInOrganization":true,"cover":{"attachmentId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","focusX":0.5,"focusY":0.3},"commentCount":4,"createdAt":"2026-10-05T15:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"put":{"operationId":"blog.schedule","summary":"Schedule the publication of a blog post","description":"Publishes the draft at the given time, exactly once, also with several nodes. A new schedule replaces the old one. If the person who scheduled it can no longer edit the post at that time, the post is held: the space admins and that person are notified, and a space admin publishes it or cancels the schedule.\n\nRequires the permission `item.publish` on the item in `postId`.","tags":["Blog"],"x-lunedo-permission":{"action":"item.publish","resource":"item","parameter":"postId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"postId","in":"path","required":true,"description":"ID of the blog post.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"at":{"description":"When to publish, in the future and at most a year ahead. ISO 8601 timestamp; an offset is allowed.","type":"string","format":"date-time"},"timeZone":{"type":"string","maxLength":100,"description":"IANA time zone the author chose the time in, such as `Europe/Vienna`."}},"required":["at","timeZone"],"additionalProperties":false,"description":"When to publish the post. A background job publishes it once at that time."},"example":{"at":"2026-10-14T07:00:00+02:00","timeZone":"Europe/Vienna"}}}},"responses":{"200":{"description":"The post with its schedule.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the blog post in the addresses of the app."},"spaceId":{"type":"string","format":"uuid","description":"Space of the post."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."},"title":{"type":"string","description":"Title as readers see it."},"excerpt":{"type":"string","description":"Short summary shown in lists."},"labels":{"type":"array","items":{"type":"string","description":"A label."},"description":"Labels, sorted."},"author":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who wrote the post, or null."},"published":{"type":"boolean","description":"Whether the post was published. Unpublished posts are visible only to editors."},"publishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post was first published, or null. ISO 8601 timestamp in UTC."},"scheduledAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post will be published, or null. ISO 8601 timestamp in UTC."},"scheduledTimeZone":{"description":"Time zone the author scheduled it in, or null.","type":["string","null"]},"scheduledBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who scheduled the publication, or null."},"held":{"type":"boolean","description":"Whether the scheduled publication is waiting for a space admin because the person who scheduled it can no longer edit the post."},"pinnedInSpace":{"type":"boolean","description":"Whether the post is pinned at the top of its space's blog."},"pinnedInOrganization":{"type":"boolean","description":"Whether the post is pinned in the organization's blog overview."},"cover":{"anyOf":[{"type":"object","properties":{"attachmentId":{"type":"string","format":"uuid","description":"The image attachment."},"focusX":{"type":"number","description":"Horizontal focal point from 0 (left) to 1 (right)."},"focusY":{"type":"number","description":"Vertical focal point from 0 (top) to 1 (bottom)."}},"required":["attachmentId","focusX","focusY"],"additionalProperties":false},{"type":"null"}],"description":"Cover image with the point that stays visible in every crop, or null."},"commentCount":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Number of comments and replies on the post that are not deleted."},"createdAt":{"type":"string","format":"date-time","description":"When the post was created. ISO 8601 timestamp in UTC."}},"required":["id","number","spaceId","spaceKey","spaceName","title","excerpt","labels","author","published","publishedAt","scheduledAt","scheduledTimeZone","scheduledBy","held","pinnedInSpace","pinnedInOrganization","cover","commentCount","createdAt"],"additionalProperties":false,"description":"A blog post."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5d01","number":1077,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","title":"New VPN client from Monday","excerpt":"The company portal ships WireGuard 0.6 on Monday.","labels":["vpn"],"author":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"published":true,"publishedAt":"2026-10-06T07:00:00.000Z","scheduledAt":"2026-10-14T05:00:00.000Z","scheduledTimeZone":"Europe/Vienna","scheduledBy":null,"held":false,"pinnedInSpace":false,"pinnedInOrganization":true,"cover":{"attachmentId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","focusX":0.5,"focusY":0.3},"commentCount":4,"createdAt":"2026-10-05T15:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidTimeZone`: The time zone is not known. `scheduleInPast`: The scheduled time lies in the past. `scheduleTooLate`: The scheduled time is too far ahead.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidTimeZone":{"value":{"type":"urn:lunedo:problem:invalidTimeZone","title":"The time zone is not known","status":400,"code":"invalidTimeZone"}},"scheduleInPast":{"value":{"type":"urn:lunedo:problem:scheduleInPast","title":"The scheduled time lies in the past","status":400,"code":"scheduleInPast"}},"scheduleTooLate":{"value":{"type":"urn:lunedo:problem:scheduleTooLate","title":"The scheduled time is too far ahead","status":400,"code":"scheduleTooLate"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/categories/{itemId}":{"put":{"operationId":"knowledgeBases.updateCategory","summary":"Change a category","description":"Sets the icon of a folder at any depth. Title, introduction and order change like for every folder; the contact address has its own route for space admins.\n\nRequires the permission `item.edit` on the item in `itemId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the category.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"icon":{"description":"Name of a Lucide icon such as `monitor`, or null to show the initial instead.","anyOf":[{"type":"string","maxLength":60},{"type":"null"}]}},"additionalProperties":false,"description":"The changes."},"example":{"icon":"monitor"}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidIcon`: The icon is not valid. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidIcon":{"value":{"type":"urn:lunedo:problem:invalidIcon","title":"The icon is not valid","status":400,"code":"invalidIcon"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notCategory`: The item is not an area or a topic.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notCategory":{"value":{"type":"urn:lunedo:problem:notCategory","title":"The item is not an area or a topic","status":409,"code":"notCategory"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/categories/{itemId}/contact":{"put":{"operationId":"knowledgeBases.setCategoryContact","summary":"Set the contact address of a category","description":"Sets the address readers write to from articles of the folder and every folder below it without an address of its own, or null to inherit it. Works at any depth. Only space admins of the knowledge base can change it.\n\nRequires the permission `item.view` on the item in `itemId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the category.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contactEmail":{"anyOf":[{"type":"string","maxLength":254},{"type":"null"}],"description":"E-mail address readers write to when an article did not help, or null."}},"required":["contactEmail"],"additionalProperties":false,"description":"The contact address."},"example":{"contactEmail":"it@example.org"}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidContactEmail`: The contact address is not valid. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidContactEmail":{"value":{"type":"urn:lunedo:problem:invalidContactEmail","title":"The contact address is not valid","status":400,"code":"invalidContactEmail"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notCategory`: The item is not an area or a topic.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notCategory":{"value":{"type":"urn:lunedo:problem:notCategory","title":"The item is not an area or a topic","status":409,"code":"notCategory"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/comments/{commentId}":{"delete":{"operationId":"comments.delete","summary":"Delete a comment","description":"Deletes a comment. Authors delete their own comments, space admins any comment; the latter is recorded in the audit log. A deleted comment with replies stays as a placeholder. Whoever deleted it can restore it within an hour.\n\nRequires the permission `comment.delete` on the comment in `commentId`.","tags":["Comments"],"x-lunedo-permission":{"action":"comment.delete","resource":"comment","parameter":"commentId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"commentId","in":"path","required":true,"description":"ID of the comment.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"put":{"operationId":"comments.update","summary":"Change a comment","description":"Changes the content of the caller's own comment. The comment is marked as edited.\n\nRequires the permission `comment.update` on the comment in `commentId`.","tags":["Comments"],"x-lunedo-permission":{"action":"comment.update","resource":"comment","parameter":"commentId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"commentId","in":"path","required":true,"description":"ID of the comment.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"description":"Comment content as ProseMirror JSON with the reduced comment schema: paragraphs with bold, italic, underline, strike, subscript, superscript, inline code and links, mentions, bullet and numbered lists and code blocks. No tables, images or headings.","$ref":"#/components/schemas/Schema113ae44d8375"}},"required":["body"],"additionalProperties":false,"description":"Comment content."},"example":{"body":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Happened twice this week."}]}]}}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidComment`: The comment does not match the comment schema. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidComment":{"value":{"type":"urn:lunedo:problem:invalidComment","title":"The comment does not match the comment schema","status":400,"code":"invalidComment"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/comments/{commentId}/reactions/{emoji}":{"delete":{"operationId":"comments.unreactToComment","summary":"Remove a reaction from a comment","description":"Removes the caller's reaction with the emoji. Removing a reaction that does not exist changes nothing.\n\nRequires the permission `comment.react` on the comment in `commentId`.","tags":["Comments"],"x-lunedo-permission":{"action":"comment.react","resource":"comment","parameter":"commentId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"commentId","in":"path","required":true,"description":"ID of the comment.","schema":{"type":"string","format":"uuid"}},{"name":"emoji","in":"path","required":true,"description":"The emoji, URL-encoded.","schema":{"type":"string","minLength":1,"maxLength":64}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"put":{"operationId":"comments.reactToComment","summary":"React to a comment","description":"Adds the caller's reaction with an emoji. Adding it again changes nothing.\n\nRequires the permission `comment.react` on the comment in `commentId`.","tags":["Comments"],"x-lunedo-permission":{"action":"comment.react","resource":"comment","parameter":"commentId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"commentId","in":"path","required":true,"description":"ID of the comment.","schema":{"type":"string","format":"uuid"}},{"name":"emoji","in":"path","required":true,"description":"The emoji, URL-encoded.","schema":{"type":"string","minLength":1,"maxLength":64}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidEmoji`: The reaction is not a single emoji. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidEmoji":{"value":{"type":"urn:lunedo:problem:invalidEmoji","title":"The reaction is not a single emoji","status":400,"code":"invalidEmoji"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`reactionsDisabled`: Reactions are turned off. `tooManyReactions`: Too many reactions from one person.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"reactionsDisabled":{"value":{"type":"urn:lunedo:problem:reactionsDisabled","title":"Reactions are turned off","status":409,"code":"reactionsDisabled"}},"tooManyReactions":{"value":{"type":"urn:lunedo:problem:tooManyReactions","title":"Too many reactions from one person","status":409,"code":"tooManyReactions"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/comments/{commentId}/replies":{"post":{"operationId":"comments.reply","summary":"Reply to a comment","description":"Adds a reply to the thread of the comment. Replies are one level deep: a reply to a reply joins the same thread.\n\nRequires the permission `comment.reply` on the comment in `commentId`.","tags":["Comments"],"x-lunedo-permission":{"action":"comment.reply","resource":"comment","parameter":"commentId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"commentId","in":"path","required":true,"description":"ID of the comment.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"description":"Comment content as ProseMirror JSON with the reduced comment schema: paragraphs with bold, italic, underline, strike, subscript, superscript, inline code and links, mentions, bullet and numbered lists and code blocks. No tables, images or headings.","$ref":"#/components/schemas/Schema113ae44d8375"}},"required":["body"],"additionalProperties":false,"description":"Comment content."},"example":{"body":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Happened twice this week."}]}]}}}}},"responses":{"201":{"description":"The new reply.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the new comment."}},"required":["id"],"additionalProperties":false,"description":"The new comment."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5b01"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidComment`: The comment does not match the comment schema. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidComment":{"value":{"type":"urn:lunedo:problem:invalidComment","title":"The comment does not match the comment schema","status":400,"code":"invalidComment"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`tooManyComments`: The page has too many comments.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"tooManyComments":{"value":{"type":"urn:lunedo:problem:tooManyComments","title":"The page has too many comments","status":409,"code":"tooManyComments"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/comments/{commentId}/resolved":{"put":{"operationId":"comments.resolve","summary":"Resolve or reopen a comment thread","description":"Resolves or reopens a thread through its first comment. Resolved inline comments are hidden from the text; resolved threads are listed as resolved.\n\nRequires the permission `comment.resolve` on the comment in `commentId`.","tags":["Comments"],"x-lunedo-permission":{"action":"comment.resolve","resource":"comment","parameter":"commentId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"commentId","in":"path","required":true,"description":"ID of the comment.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"resolved":{"type":"boolean","description":"True to resolve the inline comment, false to reopen it."}},"required":["resolved"],"additionalProperties":false,"description":"Resolved state."},"example":{"resolved":true}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `notInlineComment`: Only the first comment of a thread can be resolved.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"notInlineComment":{"value":{"type":"urn:lunedo:problem:notInlineComment","title":"Only the first comment of a thread can be resolved","status":400,"code":"notInlineComment"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/comments/{commentId}/restore":{"post":{"operationId":"comments.restore","summary":"Restore a deleted comment","description":"Brings back a comment the caller deleted within the last hour.\n\nRequires the permission `comment.restore` on the comment in `commentId`.","tags":["Comments"],"x-lunedo-permission":{"action":"comment.restore","resource":"comment","parameter":"commentId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"commentId","in":"path","required":true,"description":"ID of the comment.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`restoreExpired`: The time to restore has passed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"restoreExpired":{"value":{"type":"urn:lunedo:problem:restoreExpired","title":"The time to restore has passed","status":409,"code":"restoreExpired"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/confluence-links":{"get":{"operationId":"imports.resolveLink","summary":"Resolve an old Confluence link","description":"Finds the page imported from an old Confluence address. A link to a page the caller cannot read gives the same answer as a link to an unknown page.\n\nRequires the permission `instance.content.view` on the instance.","tags":["Imports"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"url","in":"query","required":true,"description":"The old Confluence address: with a page ID (`/pages/123/Title`, `pageId=123`), a Data Center path (`/display/KEY/Title`) or a short link (`/x/AbC`). A path without the host works too.","schema":{"type":"string","minLength":1,"maxLength":2000}}],"responses":{"200":{"description":"The page.","content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"ID of the page or blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the page or blog post in the addresses of the app."},"kind":{"type":"string","description":"Kind of the item. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","blogPost"]},"spaceKey":{"type":"string","description":"Key of its space, or empty when the caller can open the page only because it is shared."},"title":{"type":"string","description":"Title of the page."},"slug":{"type":"string","description":"Title as it appears in the address."}},"required":["itemId","number","kind","spaceKey","title","slug"],"additionalProperties":false,"description":"The Lunedo page an old Confluence link points to."},"example":{"itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0102","number":1042,"kind":"page","spaceKey":"ITOPS","title":"On-call rota","slug":"on-call-rota"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/copies/{copyId}":{"get":{"operationId":"copies.get","summary":"Get a copy","description":"Returns the state and progress of a copy the caller started. Titles, the new item and the IDs of the source and the target space appear only while the caller can still read them; otherwise the result names only the counts.\n\nRequires the permission `copy.view` on the copy in `copyId`.","tags":["Pages"],"x-lunedo-permission":{"action":"copy.view","resource":"copy","parameter":"copyId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"copyId","in":"path","required":true,"description":"ID of the copy.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The copy.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the copy."},"state":{"type":"string","description":"`queued` and `running` while a large copy runs in the background, `done` when the copy exists, `failed` when nothing was created. New values can be added in later versions; handle unknown values.","x-extensible-enum":["queued","running","done","failed"]},"title":{"type":"string","description":"Title of the copied item when the copy started, or an empty string when the caller can no longer read the copy or its source."},"descendants":{"type":"boolean","description":"Whether the items below were copied as well."},"sourceItemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The copied item, or null when it was deleted permanently since."},"targetSpaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The target space, or null when it was deleted permanently since."},"progress":{"type":"object","properties":{"done":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of items copied so far."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of items the copy creates."}},"required":["done","total"],"additionalProperties":false,"description":"Progress of a copy that runs in the background."},"copied":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of items created, once the copy is done."},"hidden":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of items below that were left out because the person copying cannot read them."},"skipped":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of items below that were left out because they cannot be copied: pages never published, meetings and their series."},"item":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the new item."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the new item in the addresses of the app."},"spaceId":{"type":"string","format":"uuid","description":"ID of its space."},"spaceKey":{"type":"string","description":"Key of its space."},"kind":{"type":"string","description":"Kind of the new item. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title of the new item."}},"required":["id","number","spaceId","spaceKey","kind","title"],"additionalProperties":false},{"type":"null"}],"description":"The new item at the top of the copy, or null until the copy is done."},"errorCode":{"description":"Why a copy failed, for example `copyChangesAccess` (access changed after the confirmation), `storageFull`, `copyInterrupted` or `copyFailed`; null otherwise.","type":["string","null"]},"createdAt":{"type":"string","format":"date-time","description":"When the copy started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the copy finished or failed, or null. ISO 8601 timestamp in UTC."}},"required":["id","state","title","descendants","sourceItemId","targetSpaceId","progress","copied","hidden","skipped","item","errorCode","createdAt","finishedAt"],"additionalProperties":false,"description":"A copy of a page, folder or whiteboard."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","state":"done","title":"VPN access","descendants":true,"sourceItemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","targetSpaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","progress":{"done":4,"total":4},"copied":4,"hidden":1,"skipped":0,"item":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a71","number":1071,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"OPS","kind":"page","title":"VPN access"},"errorCode":null,"createdAt":"2026-10-17T09:30:00.000Z","finishedAt":"2026-10-17T09:30:01.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/deleted-spaces":{"get":{"operationId":"trash.deletedSpaces","summary":"List the deleted spaces the caller can restore","description":"Lists deleted spaces in the second stage of the trash that the caller was space admin of when they were deleted, newest first, with when they will be removed for good.\n\nRequires the permission `instance.content.view` on the instance. Needs a signed-in session; API tokens are refused.","tags":["Trash"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"sessionCookie":[]}],"responses":{"200":{"description":"Trash entries of deleted spaces.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the trash entry."},"spaceId":{"type":"string","format":"uuid","description":"Space of the entry."},"spaceKey":{"type":"string","description":"Key of the space."},"spaceName":{"type":"string","description":"Name of the space."},"kind":{"type":"string","enum":["items","space"],"description":"`items` for deleted pages, folders or links, `space` for a deleted space."},"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The deleted item, or null for a space."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the deleted item in the addresses of the app, or null for a space."},"itemKind":{"anyOf":[{"type":"string","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},{"type":"null"}],"description":"Kind of the deleted item, or null for a space. New values can be added in later versions; handle unknown values."},"title":{"type":"string","description":"Title of the deleted item, or name of the space."},"descendants":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of descendants deleted with the item."},"stage":{"anyOf":[{"type":"number","const":1},{"type":"number","const":2}],"description":"1 while the entry is in the space trash, 2 after that period or after the trash was emptied; then only organization administrators can restore it."},"deletedAt":{"type":"string","format":"date-time","description":"When it was deleted. ISO 8601 timestamp in UTC."},"deletedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when the account no longer exists.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who deleted it."},"stageTwoAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the entry reached stage 2, or null. ISO 8601 timestamp in UTC."},"removedAt":{"type":"string","format":"date-time","description":"When the entry will be deleted permanently, by the current retention settings. ISO 8601 timestamp in UTC."},"formerParentEntryId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The trash entry of the page or folder this item was below, when that one is in the same trash list; restoring with `withParents=true` restores both. Null otherwise."}},"required":["id","spaceId","spaceKey","spaceName","kind","itemId","number","itemKind","title","descendants","stage","deletedAt","deletedBy","stageTwoAt","removedAt","formerParentEntryId"],"additionalProperties":false,"description":"An entry of the trash."},"description":"Trash entries."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","kind":"space","itemId":null,"number":1041,"itemKind":null,"title":"Old VPN (OpenVPN) setup","descendants":2,"stage":2,"deletedAt":"2026-10-02T10:00:00.000Z","deletedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Lukas Hofer"},"stageTwoAt":null,"removedAt":"2027-02-14T10:00:00.000Z","formerParentEntryId":null}]}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}}}}},"/api/v1/deleted-spaces/{entryId}/restore":{"post":{"operationId":"trash.restoreDeletedSpace","summary":"Restore a deleted space","description":"Restores a deleted space with its content and permissions as they were. Only people who were its space admins when it was deleted can do this, as long as they are still active members of its organization.\n\nRequires the permission `deletedSpace.restore` on the deletedSpace in `entryId`. Needs a signed-in session; API tokens are refused.","tags":["Trash"],"x-lunedo-permission":{"action":"deletedSpace.restore","resource":"deletedSpace","parameter":"entryId"},"security":[{"sessionCookie":[]}],"parameters":[{"name":"entryId","in":"path","required":true,"description":"ID of the trash entry of the deleted space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The result.","content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The restored item, or null for a space."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the restored item in the addresses of the app, or null for a space."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Where the item went: its parent, or null for the top level."},"parentEntries":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of trash entries of former parent pages restored with it, so it keeps the view restrictions it inherited."}},"required":["itemId","number","parentId","parentEntries"],"additionalProperties":false,"description":"Where the restored content went."},"example":{"itemId":null,"number":null,"parentId":null,"parentEntries":0}}}},"400":{"description":"`invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/exports":{"get":{"operationId":"exports.list","summary":"List your exports","description":"Lists your exports of the last 7 days that were not deleted, newest first.\n\nRequires the permission `instance.content.view` on the instance.","tags":["Exports"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"200":{"description":"Your exports.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the export."},"scope":{"type":"string","enum":["space","pages"],"description":"What is exported: `space` for a whole space, `pages` for a page with its subpages."},"format":{"type":"string","enum":["archive","html","markdown","print","pdf","docx","site"],"description":"What the file contains: `archive` a ZIP with every page as Markdown and HTML, `html` or `markdown` a ZIP with one of them, `print` one print-ready HTML file, `pdf` one PDF file, `docx` one Word document, `site` a ZIP with a static website of a public knowledge base."},"options":{"type":"object","properties":{"attachments":{"type":"boolean","description":"Whether the attachments are included or listed."},"comments":{"type":"boolean","description":"Whether open comments are included."},"contents":{"type":"boolean","description":"Whether a table of contents is included."},"paper":{"type":"string","enum":["a4","letter"],"description":"Paper size of `print`, `pdf` and `docx`."},"orientation":{"type":"string","enum":["portrait","landscape"],"description":"Orientation of `print`, `pdf` and `docx`."},"siteUrl":{"description":"Address the static website of `site` is served from, or null when none was given.","type":["string","null"]}},"required":["attachments","comments","contents","paper","orientation","siteUrl"],"additionalProperties":false,"description":"The options the export was started with."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The exported space, or null when it was deleted since."},"rootItemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The exported page for `pages`, or null."},"name":{"type":"string","description":"Name of the space or title of the page when the export was started."},"state":{"type":"string","enum":["queued","running","ready","failed"],"description":"`queued` waits for a worker, `running` is being built, `ready` can be downloaded, `failed` stopped with an error."},"progress":{"type":"object","properties":{"done":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Files written so far."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Files in the export, 0 until known."}},"required":["done","total"],"additionalProperties":false,"description":"Progress of a running export."},"fileName":{"description":"File name of the file once it is ready.","type":["string","null"]},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size of the file in bytes once it is ready."},"errorCode":{"anyOf":[{"type":"string","x-extensible-enum":["exportDisabled","noAccess","tokenRevoked","notEnoughStorage","renderUnavailable","renderFailed","renderTooLarge","tooManyPagesForFile","tooLargeToBuild","notPublic","interrupted","internalError"]},{"type":"null"}],"description":"Why a failed export stopped: export was turned off for the space, the permission to export the space or page was lost, the API token that started it was revoked, the file store ran short of free space while it was written, the render container for PDF is not set up or cannot be reached, it could not create the PDF, the document was larger than the render container accepts, the Word or PDF file would have more pages than the limit, building the file ran out of memory, the knowledge base of a static website is no longer public, the worker was interrupted too often, or an unexpected error. New values can be added in later versions; handle unknown values."},"createdAt":{"type":"string","format":"date-time","description":"When the export was started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the export finished or failed. ISO 8601 timestamp in UTC."},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the download is deleted: 24 hours after its first complete download, at the latest 7 days after it is ready. ISO 8601 timestamp in UTC."}},"required":["id","scope","format","options","spaceId","rootItemId","name","state","progress","fileName","size","errorCode","createdAt","finishedAt","expiresAt"],"additionalProperties":false,"description":"An export of a space or of a page with its subpages, built in the background."},"description":"Exports, newest first, at most 50."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a90","scope":"space","format":"archive","options":{"attachments":true,"comments":false,"contents":true,"paper":"a4","orientation":"portrait","siteUrl":null},"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","rootItemId":null,"name":"IT Operations","state":"ready","progress":{"done":413,"total":413},"fileName":"IT Operations 2026-10-14.zip","size":18432112,"errorCode":null,"createdAt":"2026-10-14T09:00:00.000Z","finishedAt":"2026-10-14T09:01:12.000Z","expiresAt":"2026-10-21T09:01:12.000Z"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/exports/{exportId}":{"delete":{"operationId":"exports.remove","summary":"Delete an export","description":"Deletes one of your exports and its file. A running export stops.\n\nRequires the permission `export.delete` on the export in `exportId`.","tags":["Exports"],"x-lunedo-permission":{"action":"export.delete","resource":"export","parameter":"exportId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"exportId","in":"path","required":true,"description":"ID of the export.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"get":{"operationId":"exports.get","summary":"Get an export","description":"Returns the state and progress of one of your exports.\n\nRequires the permission `export.view` on the export in `exportId`.","tags":["Exports"],"x-lunedo-permission":{"action":"export.view","resource":"export","parameter":"exportId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"exportId","in":"path","required":true,"description":"ID of the export.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The export.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the export."},"scope":{"type":"string","enum":["space","pages"],"description":"What is exported: `space` for a whole space, `pages` for a page with its subpages."},"format":{"type":"string","enum":["archive","html","markdown","print","pdf","docx","site"],"description":"What the file contains: `archive` a ZIP with every page as Markdown and HTML, `html` or `markdown` a ZIP with one of them, `print` one print-ready HTML file, `pdf` one PDF file, `docx` one Word document, `site` a ZIP with a static website of a public knowledge base."},"options":{"type":"object","properties":{"attachments":{"type":"boolean","description":"Whether the attachments are included or listed."},"comments":{"type":"boolean","description":"Whether open comments are included."},"contents":{"type":"boolean","description":"Whether a table of contents is included."},"paper":{"type":"string","enum":["a4","letter"],"description":"Paper size of `print`, `pdf` and `docx`."},"orientation":{"type":"string","enum":["portrait","landscape"],"description":"Orientation of `print`, `pdf` and `docx`."},"siteUrl":{"description":"Address the static website of `site` is served from, or null when none was given.","type":["string","null"]}},"required":["attachments","comments","contents","paper","orientation","siteUrl"],"additionalProperties":false,"description":"The options the export was started with."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The exported space, or null when it was deleted since."},"rootItemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The exported page for `pages`, or null."},"name":{"type":"string","description":"Name of the space or title of the page when the export was started."},"state":{"type":"string","enum":["queued","running","ready","failed"],"description":"`queued` waits for a worker, `running` is being built, `ready` can be downloaded, `failed` stopped with an error."},"progress":{"type":"object","properties":{"done":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Files written so far."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Files in the export, 0 until known."}},"required":["done","total"],"additionalProperties":false,"description":"Progress of a running export."},"fileName":{"description":"File name of the file once it is ready.","type":["string","null"]},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size of the file in bytes once it is ready."},"errorCode":{"anyOf":[{"type":"string","x-extensible-enum":["exportDisabled","noAccess","tokenRevoked","notEnoughStorage","renderUnavailable","renderFailed","renderTooLarge","tooManyPagesForFile","tooLargeToBuild","notPublic","interrupted","internalError"]},{"type":"null"}],"description":"Why a failed export stopped: export was turned off for the space, the permission to export the space or page was lost, the API token that started it was revoked, the file store ran short of free space while it was written, the render container for PDF is not set up or cannot be reached, it could not create the PDF, the document was larger than the render container accepts, the Word or PDF file would have more pages than the limit, building the file ran out of memory, the knowledge base of a static website is no longer public, the worker was interrupted too often, or an unexpected error. New values can be added in later versions; handle unknown values."},"createdAt":{"type":"string","format":"date-time","description":"When the export was started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the export finished or failed. ISO 8601 timestamp in UTC."},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the download is deleted: 24 hours after its first complete download, at the latest 7 days after it is ready. ISO 8601 timestamp in UTC."}},"required":["id","scope","format","options","spaceId","rootItemId","name","state","progress","fileName","size","errorCode","createdAt","finishedAt","expiresAt"],"additionalProperties":false,"description":"An export of a space or of a page with its subpages, built in the background."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a90","scope":"space","format":"archive","options":{"attachments":true,"comments":false,"contents":true,"paper":"a4","orientation":"portrait","siteUrl":null},"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","rootItemId":null,"name":"IT Operations","state":"ready","progress":{"done":413,"total":413},"fileName":"IT Operations 2026-10-14.zip","size":18432112,"errorCode":null,"createdAt":"2026-10-14T09:00:00.000Z","finishedAt":"2026-10-14T09:01:12.000Z","expiresAt":"2026-10-21T09:01:12.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/exports/{exportId}/content":{"get":{"operationId":"exports.download","summary":"Download an export","description":"Sends the file of a ready export: a ZIP archive, a print-ready HTML file, a PDF file or a Word document, depending on its format. Only the person who started it can download it, only while export is turned on for the space and they may still export what was exported. After the first complete download it is kept for 24 more hours; ranges are supported to resume an interrupted download.\n\nRequires the permission `export.download` on the export in `exportId`.","tags":["Exports"],"x-lunedo-permission":{"action":"export.download","resource":"export","parameter":"exportId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"exportId","in":"path","required":true,"description":"ID of the export.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The file or the requested part of it.","content":{"application/zip":{"schema":{"type":"string"},"example":""},"text/html":{"schema":{"type":"string"},"example":""},"application/pdf":{"schema":{"type":"string"},"example":""},"application/vnd.openxmlformats-officedocument.wordprocessingml.document":{"schema":{"type":"string"},"example":""}}},"206":{"description":"Part of the file, for a request with a `Range` header.","content":{"application/zip":{"schema":{"type":"string"},"example":""},"text/html":{"schema":{"type":"string"},"example":""},"application/pdf":{"schema":{"type":"string"},"example":""},"application/vnd.openxmlformats-officedocument.wordprocessingml.document":{"schema":{"type":"string"},"example":""}}},"304":{"description":"Not modified: the file matches the `If-None-Match` header."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`exportDisabled`: Export is turned off for this space. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"exportDisabled":{"value":{"type":"urn:lunedo:problem:exportDisabled","title":"Export is turned off for this space","status":403,"code":"exportDisabled"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"416":{"description":"`rangeNotSatisfiable`: The requested range is not available.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rangeNotSatisfiable":{"value":{"type":"urn:lunedo:problem:rangeNotSatisfiable","title":"The requested range is not available","status":416,"code":"rangeNotSatisfiable"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/groups/{groupId}":{"delete":{"operationId":"groups.delete","summary":"Delete a group","description":"Deletes the group. Roles given to the group end at once.\n\nRequires the permission `group.delete` on the group in `groupId`.","tags":["Groups"],"x-lunedo-permission":{"action":"group.delete","resource":"group","parameter":"groupId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"groupId","in":"path","required":true,"description":"ID of the group.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`groupManagedByProvider`: The group is managed by an identity provider.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"groupManagedByProvider":{"value":{"type":"urn:lunedo:problem:groupManagedByProvider","title":"The group is managed by an identity provider","status":409,"code":"groupManagedByProvider"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"get":{"operationId":"groups.get","summary":"Get a group","description":"Returns a group with its managers. List its members with `GET /api/v1/groups/{groupId}/members`.\n\nRequires the permission `group.view` on the group in `groupId`.","tags":["Groups"],"x-lunedo-permission":{"action":"group.view","resource":"group","parameter":"groupId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"groupId","in":"path","required":true,"description":"ID of the group.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The group.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the group."},"organizationId":{"type":"string","format":"uuid","description":"ID of the organization the group belongs to."},"name":{"type":"string","description":"Name of the group, unique in the organization, 1 to 100 characters."},"description":{"type":"string","description":"Description, up to 1000 characters."},"managedBy":{"description":"The identity provider that manages the members of a synchronized group, or null. Members of such a group cannot be changed in Lunedo; its permissions can.","anyOf":[{"type":"object","properties":{"providerId":{"type":"string","format":"uuid","description":"ID of the identity provider."},"providerName":{"type":"string","description":"Name of the identity provider."}},"required":["providerId","providerName"],"additionalProperties":false},{"type":"null"}]},"formerlySynchronizedFrom":{"description":"Name of the removed identity provider this group was synchronized from, or null. Such a group is an ordinary group now.","type":["string","null"]},"memberCount":{"description":"Number of active accounts in the group. Only in lists of groups.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"spaceCount":{"description":"Number of spaces that give the group a role. Only in lists of groups.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"managers":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the manager."},"name":{"type":"string","description":"Display name of the manager."}},"required":["accountId","name"],"additionalProperties":false,"description":"A manager of the group."},"description":"Accounts that manage the group's members."}},"required":["id","organizationId","name","description","managers"],"additionalProperties":false,"description":"A group with its managers. Its members are listed separately."},"example":{"id":"01929b1f-0a6d-7a51-827e-6f5a4b3c8d9e","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","name":"Editors","description":"Everyone who edits the handbook","managers":[{"accountId":"01929b1e-8d4b-7e3f-a05c-4d3e2f1a6b7c","name":"Ada Lovelace"}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"patch":{"operationId":"groups.update","summary":"Change a group","description":"Renames a group or changes its description.\n\nRequires the permission `group.manage` on the group in `groupId`.","tags":["Groups"],"x-lunedo-permission":{"action":"group.manage","resource":"group","parameter":"groupId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"groupId","in":"path","required":true,"description":"ID of the group.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"New name, 1 to 100 characters, unique in the organization.","type":"string","minLength":1,"maxLength":100},"description":{"description":"New description, up to 1000 characters.","type":"string","maxLength":1000}},"additionalProperties":false,"description":"Fields to change."},"example":{"description":"Everyone who edits or reviews the handbook"}}}},"responses":{"200":{"description":"The changed group.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the group."},"organizationId":{"type":"string","format":"uuid","description":"ID of the organization the group belongs to."},"name":{"type":"string","description":"Name of the group, unique in the organization, 1 to 100 characters."},"description":{"type":"string","description":"Description, up to 1000 characters."},"managedBy":{"description":"The identity provider that manages the members of a synchronized group, or null. Members of such a group cannot be changed in Lunedo; its permissions can.","anyOf":[{"type":"object","properties":{"providerId":{"type":"string","format":"uuid","description":"ID of the identity provider."},"providerName":{"type":"string","description":"Name of the identity provider."}},"required":["providerId","providerName"],"additionalProperties":false},{"type":"null"}]},"formerlySynchronizedFrom":{"description":"Name of the removed identity provider this group was synchronized from, or null. Such a group is an ordinary group now.","type":["string","null"]},"memberCount":{"description":"Number of active accounts in the group. Only in lists of groups.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"spaceCount":{"description":"Number of spaces that give the group a role. Only in lists of groups.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","organizationId","name","description"],"additionalProperties":false,"description":"A group of accounts."},"example":{"id":"01929b1f-0a6d-7a51-827e-6f5a4b3c8d9e","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","name":"Editors","description":"Everyone who edits the handbook"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`groupManagedByProvider`: The group is managed by an identity provider. `groupNameTaken`: The group name is taken.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"groupManagedByProvider":{"value":{"type":"urn:lunedo:problem:groupManagedByProvider","title":"The group is managed by an identity provider","status":409,"code":"groupManagedByProvider"}},"groupNameTaken":{"value":{"type":"urn:lunedo:problem:groupNameTaken","title":"The group name is taken","status":409,"code":"groupNameTaken"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/groups/{groupId}/managers":{"post":{"operationId":"groups.addManager","summary":"Add a group manager","description":"Lets a member of the organization manage the group's members.\n\nRequires the permission `group.manage` on the group in `groupId`.","tags":["Groups"],"x-lunedo-permission":{"action":"group.manage","resource":"group","parameter":"groupId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"groupId","in":"path","required":true,"description":"ID of the group.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"Account that may manage the group's members."}},"required":["accountId"],"additionalProperties":false,"description":"A new group manager."},"example":{"accountId":"01929b1e-8d4b-7e3f-a05c-4d3e2f1a6b7c"}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `notMember`: The account is not a member.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"notMember":{"value":{"type":"urn:lunedo:problem:notMember","title":"The account is not a member","status":400,"code":"notMember"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`groupManagedByProvider`: The group is managed by an identity provider.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"groupManagedByProvider":{"value":{"type":"urn:lunedo:problem:groupManagedByProvider","title":"The group is managed by an identity provider","status":409,"code":"groupManagedByProvider"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/groups/{groupId}/managers/{accountId}":{"delete":{"operationId":"groups.removeManager","summary":"Remove a group manager","description":"Takes the management of the group away from the account.\n\nRequires the permission `group.manage` on the group in `groupId`.","tags":["Groups"],"x-lunedo-permission":{"action":"group.manage","resource":"group","parameter":"groupId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"groupId","in":"path","required":true,"description":"ID of the group.","schema":{"type":"string","format":"uuid"}},{"name":"accountId","in":"path","required":true,"description":"ID of the account.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`groupManagedByProvider`: The group is managed by an identity provider.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"groupManagedByProvider":{"value":{"type":"urn:lunedo:problem:groupManagedByProvider","title":"The group is managed by an identity provider","status":409,"code":"groupManagedByProvider"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/groups/{groupId}/members":{"get":{"operationId":"groups.members","summary":"List group members","description":"Lists the current members of the group.\n\nRequires the permission `group.view` on the group in `groupId`.","tags":["Groups"],"x-lunedo-permission":{"action":"group.view","resource":"group","parameter":"groupId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"groupId","in":"path","required":true,"description":"ID of the group.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"Members of the group.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the member."},"name":{"type":"string","description":"Display name of the member."},"jobTitle":{"description":"Job title the person entered on their profile, or null.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null without one. Changes whenever the picture changes; load the picture from `GET /api/v1/accounts/{accountId}/picture`.","type":["string","null"]},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the group membership ends, or null. ISO 8601 timestamp in UTC."}},"required":["accountId","name","jobTitle","pictureRef","expiresAt"],"additionalProperties":false,"description":"A member of the group."},"description":"Members, ordered by name."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"One page of results."},"example":{"items":[{"accountId":"01929b1e-8d4b-7e3f-a05c-4d3e2f1a6b7c","name":"Ada Lovelace","jobTitle":"Head of Engineering","pictureRef":"5f2b8c1d9a0e4b7c","expiresAt":null}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"groups.addMember","summary":"Add a group member","description":"Adds a member of the organization to the group, optionally until a date. Group managers and organization administrators may add themselves; the audit log records that as a self-addition.\n\nRequires the permission `group.manage` on the group in `groupId`.","tags":["Groups"],"x-lunedo-permission":{"action":"group.manage","resource":"group","parameter":"groupId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"groupId","in":"path","required":true,"description":"ID of the group.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"Account to add. It must be a member of the organization."},"expiresAt":{"description":"When the group membership ends. ISO 8601 timestamp, or null for no expiry. Leave it out to keep the default.","anyOf":[{"description":"When the group membership ends. ISO 8601 timestamp; an offset is allowed.","type":"string","format":"date-time"},{"type":"null"}]}},"required":["accountId"],"additionalProperties":false,"description":"A new group member."},"example":{"accountId":"01929b1e-8d4b-7e3f-a05c-4d3e2f1a6b7c"}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `expiryInPast`: The expiry lies in the past. `invalidInput`: The request is not valid. `notMember`: The account is not a member.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"expiryInPast":{"value":{"type":"urn:lunedo:problem:expiryInPast","title":"The expiry lies in the past","status":400,"code":"expiryInPast"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"notMember":{"value":{"type":"urn:lunedo:problem:notMember","title":"The account is not a member","status":400,"code":"notMember"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`alreadyMember`: The account is already a member. `groupManagedByProvider`: The group is managed by an identity provider.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"alreadyMember":{"value":{"type":"urn:lunedo:problem:alreadyMember","title":"The account is already a member","status":409,"code":"alreadyMember"}},"groupManagedByProvider":{"value":{"type":"urn:lunedo:problem:groupManagedByProvider","title":"The group is managed by an identity provider","status":409,"code":"groupManagedByProvider"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/groups/{groupId}/members/{accountId}":{"delete":{"operationId":"groups.removeMember","summary":"Remove a group member","description":"Removes the account from the group.\n\nRequires the permission `group.manage` on the group in `groupId`.","tags":["Groups"],"x-lunedo-permission":{"action":"group.manage","resource":"group","parameter":"groupId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"groupId","in":"path","required":true,"description":"ID of the group.","schema":{"type":"string","format":"uuid"}},{"name":"accountId","in":"path","required":true,"description":"ID of the account.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`groupManagedByProvider`: The group is managed by an identity provider.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"groupManagedByProvider":{"value":{"type":"urn:lunedo:problem:groupManagedByProvider","title":"The group is managed by an identity provider","status":409,"code":"groupManagedByProvider"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/home":{"get":{"operationId":"home.forYou","summary":"Get the personal home page","description":"Returns what the personal home page \"For you\" shows: recently viewed items, starred items and spaces, open tasks due soon, mentions and new blog posts. Everything is limited to content the caller can read.\n\nRequires the permission `instance.content.view` on the instance.","tags":["Home"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"200":{"description":"Data of the home page.","content":{"application/json":{"schema":{"type":"object","properties":{"recent":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the page or blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app."},"kind":{"type":"string","description":"Kind of the item. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title readers see."},"spaceId":{"type":"string","format":"uuid","description":"Space of the item."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."},"mySpace":{"type":"boolean","description":"Whether the item lies in the caller's own personal space."},"viewedAt":{"type":"string","format":"date-time","description":"When the caller last viewed it. ISO 8601 timestamp in UTC."}},"required":["id","number","kind","title","spaceId","spaceKey","spaceName","mySpace","viewedAt"],"additionalProperties":false,"description":"A recently viewed item."},"description":"Items the caller viewed in the last 90 days, newest first. Only the caller sees this list."},"starred":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the page or blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app."},"kind":{"type":"string","description":"Kind of the item. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title readers see."},"spaceId":{"type":"string","format":"uuid","description":"Space of the item."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."},"mySpace":{"type":"boolean","description":"Whether the item lies in the caller's own personal space."},"starredAt":{"type":"string","format":"date-time","description":"When it was starred. ISO 8601 timestamp in UTC."}},"required":["id","number","kind","title","spaceId","spaceKey","spaceName","mySpace","starredAt"],"additionalProperties":false,"description":"A starred page or post."},"description":"Starred pages and blog posts the caller can read, newest first."},"spaces":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"name":{"type":"string","description":"Name of the space. Empty for a personal space without a name."},"personal":{"type":"boolean","description":"Whether it is a personal space."},"mySpace":{"type":"boolean","description":"Whether it is the caller's own personal space."},"starredAt":{"type":"string","format":"date-time","description":"When it was starred. ISO 8601 timestamp in UTC."}},"required":["id","key","name","personal","mySpace","starredAt"],"additionalProperties":false,"description":"A starred space."},"description":"Starred spaces the caller can read, newest first."}},"required":["items","spaces"],"additionalProperties":false,"description":"What the caller starred."},"tasks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the task."},"text":{"type":"string","description":"Text of the task, without formatting, up to 500 characters."},"done":{"type":"boolean","description":"Whether the task is done."},"dueDate":{"description":"Due date as `YYYY-MM-DD`, or null.","type":["string","null"]},"overdue":{"type":"boolean","description":"Whether the task is open and its due date lies before today in the caller's time zone."},"assignee":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"The assignee, or null."},"assignedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who assigned the task to the assignee when publishing, or null."},"item":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Page or blog post with the task."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of that item in the addresses of the app."},"kind":{"type":"string","description":"Kind of that item. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","blogPost"]},"title":{"type":"string","description":"Its title."},"spaceId":{"type":"string","format":"uuid","description":"Its space."},"spaceKey":{"type":"string","description":"Key of the space."},"spaceName":{"type":"string","description":"Name of the space."}},"required":["id","number","kind","title","spaceId","spaceKey","spaceName"],"additionalProperties":false,"description":"Where the task is."}},"required":["id","text","done","dueDate","overdue","assignee","assignedBy","item"],"additionalProperties":false,"description":"A task from published content."},"description":"The caller's open tasks due in the next 7 days or overdue."},"mentions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the mention."},"item":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the page or blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app."},"kind":{"type":"string","description":"Kind of the item. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title readers see."},"spaceId":{"type":"string","format":"uuid","description":"Space of the item."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."},"mySpace":{"type":"boolean","description":"Whether the item lies in the caller's own personal space."}},"required":["id","number","kind","title","spaceId","spaceKey","spaceName","mySpace"],"additionalProperties":false,"description":"A page or blog post."},"commentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The comment with the mention, or null for a mention in the content."},"actor":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who mentioned the caller, or null."},"at":{"type":"string","format":"date-time","description":"When the mention became visible and notified the caller. ISO 8601 timestamp in UTC."}},"required":["id","item","commentId","actor","at"],"additionalProperties":false,"description":"A mention of the caller."},"description":"The latest mentions of the caller."},"posts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the blog post in the addresses of the app."},"spaceId":{"type":"string","format":"uuid","description":"Space of the post."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."},"title":{"type":"string","description":"Title as readers see it."},"excerpt":{"type":"string","description":"Short summary shown in lists."},"labels":{"type":"array","items":{"type":"string","description":"A label."},"description":"Labels, sorted."},"author":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who wrote the post, or null."},"published":{"type":"boolean","description":"Whether the post was published. Unpublished posts are visible only to editors."},"publishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post was first published, or null. ISO 8601 timestamp in UTC."},"scheduledAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post will be published, or null. ISO 8601 timestamp in UTC."},"scheduledTimeZone":{"description":"Time zone the author scheduled it in, or null.","type":["string","null"]},"scheduledBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who scheduled the publication, or null."},"held":{"type":"boolean","description":"Whether the scheduled publication is waiting for a space admin because the person who scheduled it can no longer edit the post."},"pinnedInSpace":{"type":"boolean","description":"Whether the post is pinned at the top of its space's blog."},"pinnedInOrganization":{"type":"boolean","description":"Whether the post is pinned in the organization's blog overview."},"cover":{"anyOf":[{"type":"object","properties":{"attachmentId":{"type":"string","format":"uuid","description":"The image attachment."},"focusX":{"type":"number","description":"Horizontal focal point from 0 (left) to 1 (right)."},"focusY":{"type":"number","description":"Vertical focal point from 0 (top) to 1 (bottom)."}},"required":["attachmentId","focusX","focusY"],"additionalProperties":false},{"type":"null"}],"description":"Cover image with the point that stays visible in every crop, or null."},"commentCount":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Number of comments and replies on the post that are not deleted."},"createdAt":{"type":"string","format":"date-time","description":"When the post was created. ISO 8601 timestamp in UTC."}},"required":["id","number","spaceId","spaceKey","spaceName","title","excerpt","labels","author","published","publishedAt","scheduledAt","scheduledTimeZone","scheduledBy","held","pinnedInSpace","pinnedInOrganization","cover","commentCount","createdAt"],"additionalProperties":false,"description":"A blog post."},"description":"Blog posts of the last 30 days in spaces the caller can read."}},"required":["recent","starred","tasks","mentions","posts"],"additionalProperties":false,"description":"Data of the personal home page."},"example":{"recent":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"kind":"page","title":"VPN access for remote staff","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","mySpace":false,"viewedAt":"2026-10-07T08:00:00.000Z"}],"starred":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"kind":"page","title":"VPN access for remote staff","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","mySpace":false,"starredAt":"2026-10-06T08:00:00.000Z"}],"spaces":[]},"tasks":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5c01","text":"Add the fallback over TCP 443 for hotels","done":false,"dueDate":"2026-10-17","overdue":false,"assignee":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Lukas Hofer"},"assignedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a21","name":"Mira Klein"},"item":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"kind":"page","title":"VPN access for remote staff","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations"}}],"mentions":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5e01","item":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"kind":"page","title":"VPN access for remote staff","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","mySpace":false},"commentId":null,"actor":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"at":"2026-10-07T08:00:00.000Z"}],"posts":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5d01","number":1077,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","title":"New VPN client from Monday","excerpt":"The company portal ships WireGuard 0.6 on Monday.","labels":["vpn"],"author":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"published":true,"publishedAt":"2026-10-06T07:00:00.000Z","scheduledAt":null,"scheduledTimeZone":null,"scheduledBy":null,"held":false,"pinnedInSpace":false,"pinnedInOrganization":true,"cover":{"attachmentId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","focusX":0.5,"focusY":0.3},"commentCount":4,"createdAt":"2026-10-05T15:00:00.000Z"}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `personalOnly`: Only people have this personal data.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"personalOnly":{"value":{"type":"urn:lunedo:problem:personalOnly","title":"Only people have this personal data","status":400,"code":"personalOnly"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/imports/{importId}":{"delete":{"operationId":"imports.remove","summary":"Delete an import draft","description":"Deletes an import that has not started. Started imports are stopped or discarded instead.\n\nRequires the permission `import.manage` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.manage","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`importStarted`: The import has started.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"importStarted":{"value":{"type":"urn:lunedo:problem:importStarted","title":"The import has started","status":409,"code":"importStarted"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"get":{"operationId":"imports.get","summary":"Get an import","description":"Returns the import with its state and progress.\n\nRequires one of the permissions `import.view`, `import.takeOver` on the import in `importId`; the request decides which.","tags":["Imports"],"x-lunedo-permission":{"action":"import.view","alternatives":["import.takeOver"],"resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The import.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the import."},"organizationId":{"type":"string","format":"uuid","description":"Organization the import belongs to."},"importer":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"The administrator who imports."},"source":{"type":"string","description":"What is imported: `confluence-xml` for the XML space export of Confluence Cloud or Data Center, `confluence-csv` for the CSV space export of Confluence Cloud, `confluence-cloud` and `confluence-dc` to read a space through the Confluence API, `markdown` for a ZIP file of Markdown files, `word` for Word documents (`.docx`). New values can be added in later versions; handle unknown values.","x-extensible-enum":["confluence-xml","confluence-csv","confluence-cloud","confluence-dc","markdown","word"]},"state":{"type":"string","description":"State of the import. `draft` while the wizard is filled in, `analyzing` while the export is read, `ready` when it can be started, `running` while it imports, `held` when the importing administrator lost the permission and another administrator has to take over, `stopping` and `discarding` while the quarantine space is deleted, `review` when the quarantine space waits for a decision, `accepted`, `discarded`, `stopped` and `failed` at the end. A re-import is in `running` while it compares or applies, in `review` while changes wait for a decision, `accepted` when everything is applied, and `superseded` when a newer re-import of the same space replaced it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["draft","analyzing","ready","running","held","stopping","review","accepting","accepted","discarding","discarded","stopped","failed","superseded"]},"draftStep":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Step of the wizard the importer was on, for continuing a draft."},"file":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Where the export comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload","folder"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes, or null when not known yet."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload, or null for a file in the import folder."},"complete":{"type":"boolean","description":"Whether the file is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},{"type":"null"}],"description":"The export file, or null when none is chosen yet."},"spaceName":{"description":"Name of the new space.","type":["string","null"]},"spaceKey":{"description":"Key of the new space.","type":["string","null"]},"archived":{"type":"boolean","description":"Whether the space becomes archived when the import is accepted."},"history":{"type":"boolean","description":"Whether every Confluence version becomes a Lunedo version, or only the current state is imported."},"peopleSource":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"How people are recognized: `token` reads names and e-mail addresses with a read-only Atlassian API token, `list` uses a user list exported from the Atlassian administration, `skip` keeps every author as a placeholder, `source` takes the names Confluence Data Center returns through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["token","list","skip","source"]},"site":{"description":"Confluence site the token is used with, or null.","type":["string","null"]},"email":{"description":"Atlassian e-mail address the token belongs to, or null.","type":["string","null"]},"people":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"People of the export the token could read, or people in the user list; null when unknown."},"withEmail":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Of these, people with a visible e-mail address."}},"required":["kind","site","email","people","withEmail"],"additionalProperties":false},{"type":"null"}],"description":"How people are recognized. The token itself is never returned."},"connection":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Kind of Confluence the import reads through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["cloud","dataCenter"]},"site":{"type":"string","description":"Host name of the Confluence site, with the port when it is not 443."},"basePath":{"type":"string","description":"Context path of Confluence Data Center, such as `/confluence`, or empty."},"email":{"description":"Atlassian e-mail address the API token belongs to, or null.","type":["string","null"]},"account":{"description":"Name of the Confluence account the token belongs to.","type":["string","null"]},"selection":{"type":"array","items":{"type":"object","properties":{"importId":{"type":"string","format":"uuid","description":"ID of the import that reads the space."},"spaceKey":{"type":"string","description":"Key of the Confluence space."}},"required":["importId","spaceKey"],"additionalProperties":false},"description":"Spaces chosen with this connection whose imports are not started yet, one import per space, this import included. Empty once the import has started."}},"required":["kind","site","basePath","email","account","selection"],"additionalProperties":false},{"type":"null"}],"description":"The connection of an import through the Confluence API, or null. Several imports of the same importer can share one connection; the token is never returned."},"files":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","description":"Where the document comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload."},"complete":{"type":"boolean","description":"Whether the upload is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},"description":"The Word documents of a `word` import, in their order. Empty for other imports."},"options":{"type":"object","properties":{"spaceKey":{"description":"Key of the Confluence space read through the API or from a site backup.","type":"string"},"pageIds":{"description":"IDs of the top-level pages whose trees are imported; all pages when left out.","type":"array","items":{"type":"string"}},"blogPosts":{"description":"Whether blog posts are imported; true when left out.","type":"boolean"},"split":{"type":"string","description":"`file` makes each Word document one page, `heading` adds a subpage per top-level heading. New values can be added in later versions; handle unknown values.","x-extensible-enum":["file","heading"]},"knowledgeBase":{"description":"For a `markdown` import: whether the new space is a knowledge base.","type":"boolean"}},"additionalProperties":false,"description":"Options of the source."},"throttledUntil":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Until when Confluence asked Lunedo to slow down, or null. The import continues by itself. ISO 8601 timestamp in UTC."},"waitingFor":{"description":"Key of the Confluence space whose import over the same connection reads or runs first, or null. Imports sharing a connection run one after another; this one continues by itself.","type":["string","null"]},"tokenDeletedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the API token was deleted: when the import was accepted, discarded, stopped or failed, when the importer lost the permission to import, or when the draft was left alone for a week. ISO 8601 timestamp in UTC."},"sourceUrl":{"description":"Address of the Confluence site. Links to pages outside the export point there.","type":["string","null"]},"reviewers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"People who can read the quarantine space and the report."},"phase":{"anyOf":[{"type":"string","x-extensible-enum":["read","compare","space","people","pages","attachments","templates","content","comments","reactions","permissions","baseline","finish","lineage","moves","labels","deletions","done"]},{"type":"null"}],"description":"Step the import is in: `read` reads the export, then `space`, `people`, `pages`, `attachments`, `templates`, `content`, `comments`, `reactions`, `permissions`, `baseline` and `finish`; `done` after the last step. A re-import compares in `compare` and applies in `lineage`, `people`, `pages`, `moves`, `attachments`, `templates`, `content`, `labels`, `comments`, `reactions`, `deletions`, `baseline` and `finish`. New values can be added in later versions; handle unknown values."},"progress":{"type":"object","properties":{"done":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units done in the current step."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units of the current step, or 0 when not known."}},"required":["done","total"],"additionalProperties":false,"description":"Progress of the current step."},"found":{"anyOf":[{"type":"object","properties":{"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages in the export."},"blogPosts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Blog posts in the export."},"versions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Earlier versions of pages and blog posts."},"comments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Comments, including inline comments and replies."},"likes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Likes on pages, blog posts and comments."},"watchers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Watchers of pages and the space. They are counted, not imported."},"attachments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Attachments of these pages."},"attachmentBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the current attachment versions in bytes."},"people":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"People named in the export."},"macroKinds":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Different macros used on the pages."},"spaceKey":{"type":"string","description":"Key of the space in Confluence."},"spaceName":{"type":"string","description":"Name of the space in Confluence."}},"required":["pages","blogPosts","versions","comments","likes","watchers","attachments","attachmentBytes","people","macroKinds","spaceKey","spaceName"],"additionalProperties":false},{"type":"null"}],"description":"What the export contains, once it was read."},"sourceSpaces":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the space in Confluence."},"name":{"type":"string","description":"Name of the space in Confluence."}},"required":["key","name"],"additionalProperties":false}},{"type":"null"}],"description":"The spaces of a site backup, once it was read; choose one with `options.spaceKey`. Null for exports and backups of one space."},"counts":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"What was imported, by kind: `pages`, `blogPosts`, `versions`, `attachments`, `attachmentVersions`, `comments`, `inlineAnchored`, `inlineMoved`, `likes`, `watchers`, `people`, `peopleMatched`, `restrictions`, `groupsMissing` and `problems`."},"errorCode":{"description":"Why the export could not be read or the import failed, such as `notAnArchive`, `wrongFormat`, `archiveTooLarge`, `unsafeEntryName`, `xmlDeclaration`, `spaceChoiceRequired` (a site backup with several spaces; see `sourceSpaces`) or `internalError`.","type":["string","null"]},"quarantineSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."}},"required":["id","key"],"additionalProperties":false},{"type":"null"}],"description":"The space the import writes into."},"targetSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"name":{"type":"string","description":"Name of the space."}},"required":["id","key","name"],"additionalProperties":false},{"type":"null"}],"description":"For a re-import, the space created by the earlier import that the changes go into; otherwise null."},"reimportSpaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space a newer export of the same Confluence space can be imported into again, or null when this import offers no re-import."},"canManage":{"type":"boolean","description":"Whether the caller can change, start, stop, accept or discard the import."},"canResolve":{"type":"boolean","description":"Whether the caller can map people and groups of the import or apply a user list."},"canTakeOver":{"type":"boolean","description":"Whether the caller can take over a held import."},"startedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import finished or failed. ISO 8601 timestamp in UTC."},"decidedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import was accepted, discarded or stopped. ISO 8601 timestamp in UTC."},"fileExpiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When an uploaded file is deleted. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the import was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the import last changed. ISO 8601 timestamp in UTC."}},"required":["id","organizationId","importer","source","state","draftStep","file","spaceName","spaceKey","archived","history","peopleSource","connection","files","options","throttledUntil","waitingFor","tokenDeletedAt","sourceUrl","reviewers","phase","progress","found","sourceSpaces","counts","errorCode","quarantineSpace","targetSpace","reimportSpaceId","canManage","canResolve","canTakeOver","startedAt","finishedAt","decidedAt","fileExpiresAt","createdAt","updatedAt"],"additionalProperties":false,"description":"An import of a Confluence space."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0001","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0002","importer":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0003","name":"Alex Admin"},"source":"confluence-xml","state":"review","draftStep":3,"file":{"kind":"upload","name":"export.zip","size":1048576,"uploadId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0004","complete":true},"spaceName":"IT Operations","spaceKey":"ITOPS","archived":false,"sourceUrl":"https://example.atlassian.net/wiki","reviewers":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0005","name":"Robin Reviewer"}],"phase":null,"progress":{"done":0,"total":0},"found":{"pages":120,"blogPosts":6,"versions":340,"comments":85,"likes":30,"watchers":44,"attachments":40,"attachmentBytes":2048000,"people":12,"macroKinds":6,"spaceKey":"ITOPS","spaceName":"IT Operations"},"sourceSpaces":null,"history":false,"peopleSource":{"kind":"token","site":"example.atlassian.net","email":"alex@example.com","people":12,"withEmail":10},"connection":null,"files":[],"options":{},"throttledUntil":null,"waitingFor":null,"tokenDeletedAt":null,"counts":{"pages":120,"blogPosts":6,"attachments":40,"attachmentVersions":52,"comments":85,"people":12,"problems":7},"errorCode":null,"quarantineSpace":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0006","key":"ITOPS"},"targetSpace":null,"reimportSpaceId":null,"canManage":true,"canResolve":true,"canTakeOver":false,"startedAt":"2026-10-10T08:00:00.000Z","finishedAt":"2026-10-10T08:05:00.000Z","decidedAt":null,"fileExpiresAt":null,"createdAt":"2026-10-10T07:50:00.000Z","updatedAt":"2026-10-10T08:05:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"patch":{"operationId":"imports.update","summary":"Change an import draft","description":"Changes what is imported and into which space, until the import starts. Choosing a file starts reading it; the import is `ready` when that is done.\n\nRequires the permission `import.manage` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.manage","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"source":{"type":"string","description":"What is imported: `confluence-xml` for the XML space export of Confluence Cloud or Data Center, `confluence-csv` for the CSV space export of Confluence Cloud, `confluence-cloud` and `confluence-dc` to read a space through the Confluence API, `markdown` for a ZIP file of Markdown files, `word` for Word documents (`.docx`). New values can be added in later versions; handle unknown values.","x-extensible-enum":["confluence-xml","confluence-csv","confluence-cloud","confluence-dc","markdown","word"]},"draftStep":{"description":"Step of the wizard to continue on.","type":"integer","minimum":0,"maximum":10},"file":{"description":"The export file. Choosing a file starts reading it.","anyOf":[{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"upload","description":"A file uploaded in parts."},"uploadId":{"type":"string","format":"uuid","description":"ID of an upload of the caller. Reading starts once the upload is complete."}},"required":["kind","uploadId"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"folder","description":"A file in the import folder of the server."},"name":{"type":"string","minLength":1,"maxLength":255,"description":"Name of a file directly inside this organization's subfolder of the import folder."}},"required":["kind","name"],"additionalProperties":false}]},{"type":"null"}]},"files":{"description":"For a `word` import: all Word documents, in this order. Reading starts once every upload is complete.","maxItems":50,"type":"array","items":{"type":"string","format":"uuid","description":"ID of an upload of the caller."}},"options":{"description":"Options of the source. Changing them reads the source again.","type":"object","properties":{"spaceKey":{"description":"For an API import or a site backup: key of the Confluence space to read. Choosing it starts reading.","anyOf":[{"type":"string","maxLength":255},{"type":"null"}]},"pageIds":{"description":"For an API import: IDs of the top-level pages to import with their trees. Empty for all.","maxItems":500,"type":"array","items":{"type":"string","maxLength":19}},"blogPosts":{"description":"For an API import: whether blog posts are imported.","type":"boolean"},"split":{"description":"For a `word` import: one page per document, or a subpage per top-level heading.","type":"string","enum":["file","heading"]},"knowledgeBase":{"description":"For a `markdown` import: `true` makes the new space a knowledge base. Folders become categories, files become articles, and article types, languages, translations and sections written by a Lunedo export are kept. The knowledge base opens for the people given a role when it is accepted; choose its audience afterwards in its settings.","type":"boolean"}},"additionalProperties":false},"spaceName":{"description":"Name of the new space, 1 to 100 characters.","type":"string","maxLength":200},"spaceKey":{"description":"Key of the new space, 2 to 10 letters or digits.","type":"string","maxLength":20},"archived":{"description":"Whether the space becomes archived when accepted.","type":"boolean"},"history":{"description":"Whether every Confluence version becomes a Lunedo version. Takes noticeably longer.","type":"boolean"},"sourceUrl":{"description":"Address of the Confluence site, such as `https://example.atlassian.net/wiki`.","anyOf":[{"type":"string","maxLength":500},{"type":"null"}]}},"additionalProperties":false,"description":"Changes to an import that has not started yet."},"example":{"spaceName":"IT Operations","spaceKey":"ITOPS","archived":false}}}},"responses":{"200":{"description":"The import.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the import."},"organizationId":{"type":"string","format":"uuid","description":"Organization the import belongs to."},"importer":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"The administrator who imports."},"source":{"type":"string","description":"What is imported: `confluence-xml` for the XML space export of Confluence Cloud or Data Center, `confluence-csv` for the CSV space export of Confluence Cloud, `confluence-cloud` and `confluence-dc` to read a space through the Confluence API, `markdown` for a ZIP file of Markdown files, `word` for Word documents (`.docx`). New values can be added in later versions; handle unknown values.","x-extensible-enum":["confluence-xml","confluence-csv","confluence-cloud","confluence-dc","markdown","word"]},"state":{"type":"string","description":"State of the import. `draft` while the wizard is filled in, `analyzing` while the export is read, `ready` when it can be started, `running` while it imports, `held` when the importing administrator lost the permission and another administrator has to take over, `stopping` and `discarding` while the quarantine space is deleted, `review` when the quarantine space waits for a decision, `accepted`, `discarded`, `stopped` and `failed` at the end. A re-import is in `running` while it compares or applies, in `review` while changes wait for a decision, `accepted` when everything is applied, and `superseded` when a newer re-import of the same space replaced it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["draft","analyzing","ready","running","held","stopping","review","accepting","accepted","discarding","discarded","stopped","failed","superseded"]},"draftStep":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Step of the wizard the importer was on, for continuing a draft."},"file":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Where the export comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload","folder"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes, or null when not known yet."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload, or null for a file in the import folder."},"complete":{"type":"boolean","description":"Whether the file is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},{"type":"null"}],"description":"The export file, or null when none is chosen yet."},"spaceName":{"description":"Name of the new space.","type":["string","null"]},"spaceKey":{"description":"Key of the new space.","type":["string","null"]},"archived":{"type":"boolean","description":"Whether the space becomes archived when the import is accepted."},"history":{"type":"boolean","description":"Whether every Confluence version becomes a Lunedo version, or only the current state is imported."},"peopleSource":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"How people are recognized: `token` reads names and e-mail addresses with a read-only Atlassian API token, `list` uses a user list exported from the Atlassian administration, `skip` keeps every author as a placeholder, `source` takes the names Confluence Data Center returns through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["token","list","skip","source"]},"site":{"description":"Confluence site the token is used with, or null.","type":["string","null"]},"email":{"description":"Atlassian e-mail address the token belongs to, or null.","type":["string","null"]},"people":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"People of the export the token could read, or people in the user list; null when unknown."},"withEmail":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Of these, people with a visible e-mail address."}},"required":["kind","site","email","people","withEmail"],"additionalProperties":false},{"type":"null"}],"description":"How people are recognized. The token itself is never returned."},"connection":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Kind of Confluence the import reads through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["cloud","dataCenter"]},"site":{"type":"string","description":"Host name of the Confluence site, with the port when it is not 443."},"basePath":{"type":"string","description":"Context path of Confluence Data Center, such as `/confluence`, or empty."},"email":{"description":"Atlassian e-mail address the API token belongs to, or null.","type":["string","null"]},"account":{"description":"Name of the Confluence account the token belongs to.","type":["string","null"]},"selection":{"type":"array","items":{"type":"object","properties":{"importId":{"type":"string","format":"uuid","description":"ID of the import that reads the space."},"spaceKey":{"type":"string","description":"Key of the Confluence space."}},"required":["importId","spaceKey"],"additionalProperties":false},"description":"Spaces chosen with this connection whose imports are not started yet, one import per space, this import included. Empty once the import has started."}},"required":["kind","site","basePath","email","account","selection"],"additionalProperties":false},{"type":"null"}],"description":"The connection of an import through the Confluence API, or null. Several imports of the same importer can share one connection; the token is never returned."},"files":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","description":"Where the document comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload."},"complete":{"type":"boolean","description":"Whether the upload is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},"description":"The Word documents of a `word` import, in their order. Empty for other imports."},"options":{"type":"object","properties":{"spaceKey":{"description":"Key of the Confluence space read through the API or from a site backup.","type":"string"},"pageIds":{"description":"IDs of the top-level pages whose trees are imported; all pages when left out.","type":"array","items":{"type":"string"}},"blogPosts":{"description":"Whether blog posts are imported; true when left out.","type":"boolean"},"split":{"type":"string","description":"`file` makes each Word document one page, `heading` adds a subpage per top-level heading. New values can be added in later versions; handle unknown values.","x-extensible-enum":["file","heading"]},"knowledgeBase":{"description":"For a `markdown` import: whether the new space is a knowledge base.","type":"boolean"}},"additionalProperties":false,"description":"Options of the source."},"throttledUntil":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Until when Confluence asked Lunedo to slow down, or null. The import continues by itself. ISO 8601 timestamp in UTC."},"waitingFor":{"description":"Key of the Confluence space whose import over the same connection reads or runs first, or null. Imports sharing a connection run one after another; this one continues by itself.","type":["string","null"]},"tokenDeletedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the API token was deleted: when the import was accepted, discarded, stopped or failed, when the importer lost the permission to import, or when the draft was left alone for a week. ISO 8601 timestamp in UTC."},"sourceUrl":{"description":"Address of the Confluence site. Links to pages outside the export point there.","type":["string","null"]},"reviewers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"People who can read the quarantine space and the report."},"phase":{"anyOf":[{"type":"string","x-extensible-enum":["read","compare","space","people","pages","attachments","templates","content","comments","reactions","permissions","baseline","finish","lineage","moves","labels","deletions","done"]},{"type":"null"}],"description":"Step the import is in: `read` reads the export, then `space`, `people`, `pages`, `attachments`, `templates`, `content`, `comments`, `reactions`, `permissions`, `baseline` and `finish`; `done` after the last step. A re-import compares in `compare` and applies in `lineage`, `people`, `pages`, `moves`, `attachments`, `templates`, `content`, `labels`, `comments`, `reactions`, `deletions`, `baseline` and `finish`. New values can be added in later versions; handle unknown values."},"progress":{"type":"object","properties":{"done":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units done in the current step."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units of the current step, or 0 when not known."}},"required":["done","total"],"additionalProperties":false,"description":"Progress of the current step."},"found":{"anyOf":[{"type":"object","properties":{"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages in the export."},"blogPosts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Blog posts in the export."},"versions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Earlier versions of pages and blog posts."},"comments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Comments, including inline comments and replies."},"likes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Likes on pages, blog posts and comments."},"watchers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Watchers of pages and the space. They are counted, not imported."},"attachments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Attachments of these pages."},"attachmentBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the current attachment versions in bytes."},"people":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"People named in the export."},"macroKinds":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Different macros used on the pages."},"spaceKey":{"type":"string","description":"Key of the space in Confluence."},"spaceName":{"type":"string","description":"Name of the space in Confluence."}},"required":["pages","blogPosts","versions","comments","likes","watchers","attachments","attachmentBytes","people","macroKinds","spaceKey","spaceName"],"additionalProperties":false},{"type":"null"}],"description":"What the export contains, once it was read."},"sourceSpaces":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the space in Confluence."},"name":{"type":"string","description":"Name of the space in Confluence."}},"required":["key","name"],"additionalProperties":false}},{"type":"null"}],"description":"The spaces of a site backup, once it was read; choose one with `options.spaceKey`. Null for exports and backups of one space."},"counts":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"What was imported, by kind: `pages`, `blogPosts`, `versions`, `attachments`, `attachmentVersions`, `comments`, `inlineAnchored`, `inlineMoved`, `likes`, `watchers`, `people`, `peopleMatched`, `restrictions`, `groupsMissing` and `problems`."},"errorCode":{"description":"Why the export could not be read or the import failed, such as `notAnArchive`, `wrongFormat`, `archiveTooLarge`, `unsafeEntryName`, `xmlDeclaration`, `spaceChoiceRequired` (a site backup with several spaces; see `sourceSpaces`) or `internalError`.","type":["string","null"]},"quarantineSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."}},"required":["id","key"],"additionalProperties":false},{"type":"null"}],"description":"The space the import writes into."},"targetSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"name":{"type":"string","description":"Name of the space."}},"required":["id","key","name"],"additionalProperties":false},{"type":"null"}],"description":"For a re-import, the space created by the earlier import that the changes go into; otherwise null."},"reimportSpaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space a newer export of the same Confluence space can be imported into again, or null when this import offers no re-import."},"canManage":{"type":"boolean","description":"Whether the caller can change, start, stop, accept or discard the import."},"canResolve":{"type":"boolean","description":"Whether the caller can map people and groups of the import or apply a user list."},"canTakeOver":{"type":"boolean","description":"Whether the caller can take over a held import."},"startedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import finished or failed. ISO 8601 timestamp in UTC."},"decidedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import was accepted, discarded or stopped. ISO 8601 timestamp in UTC."},"fileExpiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When an uploaded file is deleted. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the import was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the import last changed. ISO 8601 timestamp in UTC."}},"required":["id","organizationId","importer","source","state","draftStep","file","spaceName","spaceKey","archived","history","peopleSource","connection","files","options","throttledUntil","waitingFor","tokenDeletedAt","sourceUrl","reviewers","phase","progress","found","sourceSpaces","counts","errorCode","quarantineSpace","targetSpace","reimportSpaceId","canManage","canResolve","canTakeOver","startedAt","finishedAt","decidedAt","fileExpiresAt","createdAt","updatedAt"],"additionalProperties":false,"description":"An import of a Confluence space."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0001","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0002","importer":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0003","name":"Alex Admin"},"source":"confluence-xml","state":"ready","draftStep":3,"file":{"kind":"upload","name":"export.zip","size":1048576,"uploadId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0004","complete":true},"spaceName":"IT Operations","spaceKey":"ITOPS","archived":false,"sourceUrl":"https://example.atlassian.net/wiki","reviewers":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0005","name":"Robin Reviewer"}],"phase":null,"progress":{"done":0,"total":0},"found":{"pages":120,"blogPosts":6,"versions":340,"comments":85,"likes":30,"watchers":44,"attachments":40,"attachmentBytes":2048000,"people":12,"macroKinds":6,"spaceKey":"ITOPS","spaceName":"IT Operations"},"sourceSpaces":null,"history":false,"peopleSource":{"kind":"token","site":"example.atlassian.net","email":"alex@example.com","people":12,"withEmail":10},"connection":null,"files":[],"options":{},"throttledUntil":null,"waitingFor":null,"tokenDeletedAt":null,"counts":{"pages":120,"blogPosts":6,"attachments":40,"attachmentVersions":52,"comments":85,"people":12,"problems":7},"errorCode":null,"quarantineSpace":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0006","key":"ITOPS"},"targetSpace":null,"reimportSpaceId":null,"canManage":true,"canResolve":true,"canTakeOver":false,"startedAt":"2026-10-10T08:00:00.000Z","finishedAt":"2026-10-10T08:05:00.000Z","decidedAt":null,"fileExpiresAt":null,"createdAt":"2026-10-10T07:50:00.000Z","updatedAt":"2026-10-10T08:05:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidOptions`: The options do not apply to this import. `invalidSelection`: The selection is not valid. `invalidSourceUrl`: The address of the source site is not valid. `invalidSpaceKey`: The space key is not valid. `invalidSpaceName`: The space name is not valid. `macroDocument`: Word documents with macros are not imported. `tooManyFiles`: Too many files for one import. `wrongFileType`: The file has the wrong type for this import. `wrongInput`: This kind of import does not take this input.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidOptions":{"value":{"type":"urn:lunedo:problem:invalidOptions","title":"The options do not apply to this import","status":400,"code":"invalidOptions"}},"invalidSelection":{"value":{"type":"urn:lunedo:problem:invalidSelection","title":"The selection is not valid","status":400,"code":"invalidSelection"}},"invalidSourceUrl":{"value":{"type":"urn:lunedo:problem:invalidSourceUrl","title":"The address of the source site is not valid","status":400,"code":"invalidSourceUrl"}},"invalidSpaceKey":{"value":{"type":"urn:lunedo:problem:invalidSpaceKey","title":"The space key is not valid","status":400,"code":"invalidSpaceKey"}},"invalidSpaceName":{"value":{"type":"urn:lunedo:problem:invalidSpaceName","title":"The space name is not valid","status":400,"code":"invalidSpaceName"}},"macroDocument":{"value":{"type":"urn:lunedo:problem:macroDocument","title":"Word documents with macros are not imported","status":400,"code":"macroDocument"}},"tooManyFiles":{"value":{"type":"urn:lunedo:problem:tooManyFiles","title":"Too many files for one import","status":400,"code":"tooManyFiles"}},"wrongFileType":{"value":{"type":"urn:lunedo:problem:wrongFileType","title":"The file has the wrong type for this import","status":400,"code":"wrongFileType"}},"wrongInput":{"value":{"type":"urn:lunedo:problem:wrongInput","title":"This kind of import does not take this input","status":400,"code":"wrongInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`importFileUnavailable`: The file is not in the import folder. `importFolderDisabled`: The import folder is turned off. `importStarted`: The import has started. `uploadIncomplete`: The upload is not complete.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"importFileUnavailable":{"value":{"type":"urn:lunedo:problem:importFileUnavailable","title":"The file is not in the import folder","status":409,"code":"importFileUnavailable"}},"importFolderDisabled":{"value":{"type":"urn:lunedo:problem:importFolderDisabled","title":"The import folder is turned off","status":409,"code":"importFolderDisabled"}},"importStarted":{"value":{"type":"urn:lunedo:problem:importStarted","title":"The import has started","status":409,"code":"importStarted"}},"uploadIncomplete":{"value":{"type":"urn:lunedo:problem:uploadIncomplete","title":"The upload is not complete","status":409,"code":"uploadIncomplete"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/imports/{importId}/accept":{"post":{"operationId":"imports.accept","summary":"Accept an import","description":"Turns the quarantine space into a regular space with the given access, archived when the import asked for it. The importing administrator becomes space admin.\n\nRequires the permission `import.manage` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.manage","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"visibility":{"type":"string","enum":["private","organization","instance"],"description":"Who can read the space besides its holders: `private` (only holders), `organization` (every member of the organization) or `instance` (every internal user of the instance)."},"grants":{"maxItems":100,"type":"array","items":{"type":"object","properties":{"principalKind":{"type":"string","enum":["account","group","organizationMembers","instanceUsers"],"description":"Holder of a role: an account (person or service account), a group, all members of the organization, or all internal users of the instance."},"principalId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the account or group; null for all members and all internal users."},"role":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."}},"required":["principalKind","principalId","role"],"additionalProperties":false,"description":"A role for a holder."},"description":"Roles in the space. The importing administrator always becomes space admin in addition."}},"required":["visibility","grants"],"additionalProperties":false,"description":"Who gets access when the import is accepted."},"example":{"visibility":"organization","grants":[{"principalKind":"organizationMembers","principalId":null,"role":"editor"}]}}}},"responses":{"200":{"description":"The import.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the import."},"organizationId":{"type":"string","format":"uuid","description":"Organization the import belongs to."},"importer":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"The administrator who imports."},"source":{"type":"string","description":"What is imported: `confluence-xml` for the XML space export of Confluence Cloud or Data Center, `confluence-csv` for the CSV space export of Confluence Cloud, `confluence-cloud` and `confluence-dc` to read a space through the Confluence API, `markdown` for a ZIP file of Markdown files, `word` for Word documents (`.docx`). New values can be added in later versions; handle unknown values.","x-extensible-enum":["confluence-xml","confluence-csv","confluence-cloud","confluence-dc","markdown","word"]},"state":{"type":"string","description":"State of the import. `draft` while the wizard is filled in, `analyzing` while the export is read, `ready` when it can be started, `running` while it imports, `held` when the importing administrator lost the permission and another administrator has to take over, `stopping` and `discarding` while the quarantine space is deleted, `review` when the quarantine space waits for a decision, `accepted`, `discarded`, `stopped` and `failed` at the end. A re-import is in `running` while it compares or applies, in `review` while changes wait for a decision, `accepted` when everything is applied, and `superseded` when a newer re-import of the same space replaced it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["draft","analyzing","ready","running","held","stopping","review","accepting","accepted","discarding","discarded","stopped","failed","superseded"]},"draftStep":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Step of the wizard the importer was on, for continuing a draft."},"file":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Where the export comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload","folder"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes, or null when not known yet."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload, or null for a file in the import folder."},"complete":{"type":"boolean","description":"Whether the file is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},{"type":"null"}],"description":"The export file, or null when none is chosen yet."},"spaceName":{"description":"Name of the new space.","type":["string","null"]},"spaceKey":{"description":"Key of the new space.","type":["string","null"]},"archived":{"type":"boolean","description":"Whether the space becomes archived when the import is accepted."},"history":{"type":"boolean","description":"Whether every Confluence version becomes a Lunedo version, or only the current state is imported."},"peopleSource":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"How people are recognized: `token` reads names and e-mail addresses with a read-only Atlassian API token, `list` uses a user list exported from the Atlassian administration, `skip` keeps every author as a placeholder, `source` takes the names Confluence Data Center returns through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["token","list","skip","source"]},"site":{"description":"Confluence site the token is used with, or null.","type":["string","null"]},"email":{"description":"Atlassian e-mail address the token belongs to, or null.","type":["string","null"]},"people":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"People of the export the token could read, or people in the user list; null when unknown."},"withEmail":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Of these, people with a visible e-mail address."}},"required":["kind","site","email","people","withEmail"],"additionalProperties":false},{"type":"null"}],"description":"How people are recognized. The token itself is never returned."},"connection":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Kind of Confluence the import reads through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["cloud","dataCenter"]},"site":{"type":"string","description":"Host name of the Confluence site, with the port when it is not 443."},"basePath":{"type":"string","description":"Context path of Confluence Data Center, such as `/confluence`, or empty."},"email":{"description":"Atlassian e-mail address the API token belongs to, or null.","type":["string","null"]},"account":{"description":"Name of the Confluence account the token belongs to.","type":["string","null"]},"selection":{"type":"array","items":{"type":"object","properties":{"importId":{"type":"string","format":"uuid","description":"ID of the import that reads the space."},"spaceKey":{"type":"string","description":"Key of the Confluence space."}},"required":["importId","spaceKey"],"additionalProperties":false},"description":"Spaces chosen with this connection whose imports are not started yet, one import per space, this import included. Empty once the import has started."}},"required":["kind","site","basePath","email","account","selection"],"additionalProperties":false},{"type":"null"}],"description":"The connection of an import through the Confluence API, or null. Several imports of the same importer can share one connection; the token is never returned."},"files":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","description":"Where the document comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload."},"complete":{"type":"boolean","description":"Whether the upload is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},"description":"The Word documents of a `word` import, in their order. Empty for other imports."},"options":{"type":"object","properties":{"spaceKey":{"description":"Key of the Confluence space read through the API or from a site backup.","type":"string"},"pageIds":{"description":"IDs of the top-level pages whose trees are imported; all pages when left out.","type":"array","items":{"type":"string"}},"blogPosts":{"description":"Whether blog posts are imported; true when left out.","type":"boolean"},"split":{"type":"string","description":"`file` makes each Word document one page, `heading` adds a subpage per top-level heading. New values can be added in later versions; handle unknown values.","x-extensible-enum":["file","heading"]},"knowledgeBase":{"description":"For a `markdown` import: whether the new space is a knowledge base.","type":"boolean"}},"additionalProperties":false,"description":"Options of the source."},"throttledUntil":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Until when Confluence asked Lunedo to slow down, or null. The import continues by itself. ISO 8601 timestamp in UTC."},"waitingFor":{"description":"Key of the Confluence space whose import over the same connection reads or runs first, or null. Imports sharing a connection run one after another; this one continues by itself.","type":["string","null"]},"tokenDeletedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the API token was deleted: when the import was accepted, discarded, stopped or failed, when the importer lost the permission to import, or when the draft was left alone for a week. ISO 8601 timestamp in UTC."},"sourceUrl":{"description":"Address of the Confluence site. Links to pages outside the export point there.","type":["string","null"]},"reviewers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"People who can read the quarantine space and the report."},"phase":{"anyOf":[{"type":"string","x-extensible-enum":["read","compare","space","people","pages","attachments","templates","content","comments","reactions","permissions","baseline","finish","lineage","moves","labels","deletions","done"]},{"type":"null"}],"description":"Step the import is in: `read` reads the export, then `space`, `people`, `pages`, `attachments`, `templates`, `content`, `comments`, `reactions`, `permissions`, `baseline` and `finish`; `done` after the last step. A re-import compares in `compare` and applies in `lineage`, `people`, `pages`, `moves`, `attachments`, `templates`, `content`, `labels`, `comments`, `reactions`, `deletions`, `baseline` and `finish`. New values can be added in later versions; handle unknown values."},"progress":{"type":"object","properties":{"done":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units done in the current step."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units of the current step, or 0 when not known."}},"required":["done","total"],"additionalProperties":false,"description":"Progress of the current step."},"found":{"anyOf":[{"type":"object","properties":{"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages in the export."},"blogPosts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Blog posts in the export."},"versions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Earlier versions of pages and blog posts."},"comments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Comments, including inline comments and replies."},"likes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Likes on pages, blog posts and comments."},"watchers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Watchers of pages and the space. They are counted, not imported."},"attachments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Attachments of these pages."},"attachmentBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the current attachment versions in bytes."},"people":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"People named in the export."},"macroKinds":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Different macros used on the pages."},"spaceKey":{"type":"string","description":"Key of the space in Confluence."},"spaceName":{"type":"string","description":"Name of the space in Confluence."}},"required":["pages","blogPosts","versions","comments","likes","watchers","attachments","attachmentBytes","people","macroKinds","spaceKey","spaceName"],"additionalProperties":false},{"type":"null"}],"description":"What the export contains, once it was read."},"sourceSpaces":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the space in Confluence."},"name":{"type":"string","description":"Name of the space in Confluence."}},"required":["key","name"],"additionalProperties":false}},{"type":"null"}],"description":"The spaces of a site backup, once it was read; choose one with `options.spaceKey`. Null for exports and backups of one space."},"counts":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"What was imported, by kind: `pages`, `blogPosts`, `versions`, `attachments`, `attachmentVersions`, `comments`, `inlineAnchored`, `inlineMoved`, `likes`, `watchers`, `people`, `peopleMatched`, `restrictions`, `groupsMissing` and `problems`."},"errorCode":{"description":"Why the export could not be read or the import failed, such as `notAnArchive`, `wrongFormat`, `archiveTooLarge`, `unsafeEntryName`, `xmlDeclaration`, `spaceChoiceRequired` (a site backup with several spaces; see `sourceSpaces`) or `internalError`.","type":["string","null"]},"quarantineSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."}},"required":["id","key"],"additionalProperties":false},{"type":"null"}],"description":"The space the import writes into."},"targetSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"name":{"type":"string","description":"Name of the space."}},"required":["id","key","name"],"additionalProperties":false},{"type":"null"}],"description":"For a re-import, the space created by the earlier import that the changes go into; otherwise null."},"reimportSpaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space a newer export of the same Confluence space can be imported into again, or null when this import offers no re-import."},"canManage":{"type":"boolean","description":"Whether the caller can change, start, stop, accept or discard the import."},"canResolve":{"type":"boolean","description":"Whether the caller can map people and groups of the import or apply a user list."},"canTakeOver":{"type":"boolean","description":"Whether the caller can take over a held import."},"startedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import finished or failed. ISO 8601 timestamp in UTC."},"decidedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import was accepted, discarded or stopped. ISO 8601 timestamp in UTC."},"fileExpiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When an uploaded file is deleted. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the import was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the import last changed. ISO 8601 timestamp in UTC."}},"required":["id","organizationId","importer","source","state","draftStep","file","spaceName","spaceKey","archived","history","peopleSource","connection","files","options","throttledUntil","waitingFor","tokenDeletedAt","sourceUrl","reviewers","phase","progress","found","sourceSpaces","counts","errorCode","quarantineSpace","targetSpace","reimportSpaceId","canManage","canResolve","canTakeOver","startedAt","finishedAt","decidedAt","fileExpiresAt","createdAt","updatedAt"],"additionalProperties":false,"description":"An import of a Confluence space."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0001","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0002","importer":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0003","name":"Alex Admin"},"source":"confluence-xml","state":"accepted","draftStep":3,"file":{"kind":"upload","name":"export.zip","size":1048576,"uploadId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0004","complete":true},"spaceName":"IT Operations","spaceKey":"ITOPS","archived":false,"sourceUrl":"https://example.atlassian.net/wiki","reviewers":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0005","name":"Robin Reviewer"}],"phase":null,"progress":{"done":0,"total":0},"found":{"pages":120,"blogPosts":6,"versions":340,"comments":85,"likes":30,"watchers":44,"attachments":40,"attachmentBytes":2048000,"people":12,"macroKinds":6,"spaceKey":"ITOPS","spaceName":"IT Operations"},"sourceSpaces":null,"history":false,"peopleSource":{"kind":"token","site":"example.atlassian.net","email":"alex@example.com","people":12,"withEmail":10},"connection":null,"files":[],"options":{},"throttledUntil":null,"waitingFor":null,"tokenDeletedAt":null,"counts":{"pages":120,"blogPosts":6,"attachments":40,"attachmentVersions":52,"comments":85,"people":12,"problems":7},"errorCode":null,"quarantineSpace":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0006","key":"ITOPS"},"targetSpace":null,"reimportSpaceId":null,"canManage":true,"canResolve":true,"canTakeOver":false,"startedAt":"2026-10-10T08:00:00.000Z","finishedAt":"2026-10-10T08:05:00.000Z","decidedAt":null,"fileExpiresAt":null,"createdAt":"2026-10-10T07:50:00.000Z","updatedAt":"2026-10-10T08:05:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`importNotInReview`: The import is not waiting for a decision. `privateSpaceBroadGrant`: A private space gives roles to people and groups only.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"importNotInReview":{"value":{"type":"urn:lunedo:problem:importNotInReview","title":"The import is not waiting for a decision","status":409,"code":"importNotInReview"}},"privateSpaceBroadGrant":{"value":{"type":"urn:lunedo:problem:privateSpaceBroadGrant","title":"A private space gives roles to people and groups only","status":409,"code":"privateSpaceBroadGrant"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/imports/{importId}/apply":{"post":{"operationId":"imports.apply","summary":"Apply the changes of a re-import","description":"Applies the changes in the background: new items are created, items changed only at the source get a new version, moves follow the source, and decided conflicts and deletions are carried out. Undecided conflicts and deletions wait. Permissions never change. Applying again changes nothing that was applied already.\n\nRequires the permission `import.resolve` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.resolve","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The re-import.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the import."},"organizationId":{"type":"string","format":"uuid","description":"Organization the import belongs to."},"importer":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"The administrator who imports."},"source":{"type":"string","description":"What is imported: `confluence-xml` for the XML space export of Confluence Cloud or Data Center, `confluence-csv` for the CSV space export of Confluence Cloud, `confluence-cloud` and `confluence-dc` to read a space through the Confluence API, `markdown` for a ZIP file of Markdown files, `word` for Word documents (`.docx`). New values can be added in later versions; handle unknown values.","x-extensible-enum":["confluence-xml","confluence-csv","confluence-cloud","confluence-dc","markdown","word"]},"state":{"type":"string","description":"State of the import. `draft` while the wizard is filled in, `analyzing` while the export is read, `ready` when it can be started, `running` while it imports, `held` when the importing administrator lost the permission and another administrator has to take over, `stopping` and `discarding` while the quarantine space is deleted, `review` when the quarantine space waits for a decision, `accepted`, `discarded`, `stopped` and `failed` at the end. A re-import is in `running` while it compares or applies, in `review` while changes wait for a decision, `accepted` when everything is applied, and `superseded` when a newer re-import of the same space replaced it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["draft","analyzing","ready","running","held","stopping","review","accepting","accepted","discarding","discarded","stopped","failed","superseded"]},"draftStep":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Step of the wizard the importer was on, for continuing a draft."},"file":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Where the export comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload","folder"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes, or null when not known yet."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload, or null for a file in the import folder."},"complete":{"type":"boolean","description":"Whether the file is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},{"type":"null"}],"description":"The export file, or null when none is chosen yet."},"spaceName":{"description":"Name of the new space.","type":["string","null"]},"spaceKey":{"description":"Key of the new space.","type":["string","null"]},"archived":{"type":"boolean","description":"Whether the space becomes archived when the import is accepted."},"history":{"type":"boolean","description":"Whether every Confluence version becomes a Lunedo version, or only the current state is imported."},"peopleSource":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"How people are recognized: `token` reads names and e-mail addresses with a read-only Atlassian API token, `list` uses a user list exported from the Atlassian administration, `skip` keeps every author as a placeholder, `source` takes the names Confluence Data Center returns through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["token","list","skip","source"]},"site":{"description":"Confluence site the token is used with, or null.","type":["string","null"]},"email":{"description":"Atlassian e-mail address the token belongs to, or null.","type":["string","null"]},"people":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"People of the export the token could read, or people in the user list; null when unknown."},"withEmail":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Of these, people with a visible e-mail address."}},"required":["kind","site","email","people","withEmail"],"additionalProperties":false},{"type":"null"}],"description":"How people are recognized. The token itself is never returned."},"connection":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Kind of Confluence the import reads through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["cloud","dataCenter"]},"site":{"type":"string","description":"Host name of the Confluence site, with the port when it is not 443."},"basePath":{"type":"string","description":"Context path of Confluence Data Center, such as `/confluence`, or empty."},"email":{"description":"Atlassian e-mail address the API token belongs to, or null.","type":["string","null"]},"account":{"description":"Name of the Confluence account the token belongs to.","type":["string","null"]},"selection":{"type":"array","items":{"type":"object","properties":{"importId":{"type":"string","format":"uuid","description":"ID of the import that reads the space."},"spaceKey":{"type":"string","description":"Key of the Confluence space."}},"required":["importId","spaceKey"],"additionalProperties":false},"description":"Spaces chosen with this connection whose imports are not started yet, one import per space, this import included. Empty once the import has started."}},"required":["kind","site","basePath","email","account","selection"],"additionalProperties":false},{"type":"null"}],"description":"The connection of an import through the Confluence API, or null. Several imports of the same importer can share one connection; the token is never returned."},"files":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","description":"Where the document comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload."},"complete":{"type":"boolean","description":"Whether the upload is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},"description":"The Word documents of a `word` import, in their order. Empty for other imports."},"options":{"type":"object","properties":{"spaceKey":{"description":"Key of the Confluence space read through the API or from a site backup.","type":"string"},"pageIds":{"description":"IDs of the top-level pages whose trees are imported; all pages when left out.","type":"array","items":{"type":"string"}},"blogPosts":{"description":"Whether blog posts are imported; true when left out.","type":"boolean"},"split":{"type":"string","description":"`file` makes each Word document one page, `heading` adds a subpage per top-level heading. New values can be added in later versions; handle unknown values.","x-extensible-enum":["file","heading"]},"knowledgeBase":{"description":"For a `markdown` import: whether the new space is a knowledge base.","type":"boolean"}},"additionalProperties":false,"description":"Options of the source."},"throttledUntil":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Until when Confluence asked Lunedo to slow down, or null. The import continues by itself. ISO 8601 timestamp in UTC."},"waitingFor":{"description":"Key of the Confluence space whose import over the same connection reads or runs first, or null. Imports sharing a connection run one after another; this one continues by itself.","type":["string","null"]},"tokenDeletedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the API token was deleted: when the import was accepted, discarded, stopped or failed, when the importer lost the permission to import, or when the draft was left alone for a week. ISO 8601 timestamp in UTC."},"sourceUrl":{"description":"Address of the Confluence site. Links to pages outside the export point there.","type":["string","null"]},"reviewers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"People who can read the quarantine space and the report."},"phase":{"anyOf":[{"type":"string","x-extensible-enum":["read","compare","space","people","pages","attachments","templates","content","comments","reactions","permissions","baseline","finish","lineage","moves","labels","deletions","done"]},{"type":"null"}],"description":"Step the import is in: `read` reads the export, then `space`, `people`, `pages`, `attachments`, `templates`, `content`, `comments`, `reactions`, `permissions`, `baseline` and `finish`; `done` after the last step. A re-import compares in `compare` and applies in `lineage`, `people`, `pages`, `moves`, `attachments`, `templates`, `content`, `labels`, `comments`, `reactions`, `deletions`, `baseline` and `finish`. New values can be added in later versions; handle unknown values."},"progress":{"type":"object","properties":{"done":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units done in the current step."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units of the current step, or 0 when not known."}},"required":["done","total"],"additionalProperties":false,"description":"Progress of the current step."},"found":{"anyOf":[{"type":"object","properties":{"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages in the export."},"blogPosts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Blog posts in the export."},"versions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Earlier versions of pages and blog posts."},"comments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Comments, including inline comments and replies."},"likes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Likes on pages, blog posts and comments."},"watchers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Watchers of pages and the space. They are counted, not imported."},"attachments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Attachments of these pages."},"attachmentBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the current attachment versions in bytes."},"people":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"People named in the export."},"macroKinds":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Different macros used on the pages."},"spaceKey":{"type":"string","description":"Key of the space in Confluence."},"spaceName":{"type":"string","description":"Name of the space in Confluence."}},"required":["pages","blogPosts","versions","comments","likes","watchers","attachments","attachmentBytes","people","macroKinds","spaceKey","spaceName"],"additionalProperties":false},{"type":"null"}],"description":"What the export contains, once it was read."},"sourceSpaces":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the space in Confluence."},"name":{"type":"string","description":"Name of the space in Confluence."}},"required":["key","name"],"additionalProperties":false}},{"type":"null"}],"description":"The spaces of a site backup, once it was read; choose one with `options.spaceKey`. Null for exports and backups of one space."},"counts":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"What was imported, by kind: `pages`, `blogPosts`, `versions`, `attachments`, `attachmentVersions`, `comments`, `inlineAnchored`, `inlineMoved`, `likes`, `watchers`, `people`, `peopleMatched`, `restrictions`, `groupsMissing` and `problems`."},"errorCode":{"description":"Why the export could not be read or the import failed, such as `notAnArchive`, `wrongFormat`, `archiveTooLarge`, `unsafeEntryName`, `xmlDeclaration`, `spaceChoiceRequired` (a site backup with several spaces; see `sourceSpaces`) or `internalError`.","type":["string","null"]},"quarantineSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."}},"required":["id","key"],"additionalProperties":false},{"type":"null"}],"description":"The space the import writes into."},"targetSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"name":{"type":"string","description":"Name of the space."}},"required":["id","key","name"],"additionalProperties":false},{"type":"null"}],"description":"For a re-import, the space created by the earlier import that the changes go into; otherwise null."},"reimportSpaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space a newer export of the same Confluence space can be imported into again, or null when this import offers no re-import."},"canManage":{"type":"boolean","description":"Whether the caller can change, start, stop, accept or discard the import."},"canResolve":{"type":"boolean","description":"Whether the caller can map people and groups of the import or apply a user list."},"canTakeOver":{"type":"boolean","description":"Whether the caller can take over a held import."},"startedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import finished or failed. ISO 8601 timestamp in UTC."},"decidedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import was accepted, discarded or stopped. ISO 8601 timestamp in UTC."},"fileExpiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When an uploaded file is deleted. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the import was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the import last changed. ISO 8601 timestamp in UTC."}},"required":["id","organizationId","importer","source","state","draftStep","file","spaceName","spaceKey","archived","history","peopleSource","connection","files","options","throttledUntil","waitingFor","tokenDeletedAt","sourceUrl","reviewers","phase","progress","found","sourceSpaces","counts","errorCode","quarantineSpace","targetSpace","reimportSpaceId","canManage","canResolve","canTakeOver","startedAt","finishedAt","decidedAt","fileExpiresAt","createdAt","updatedAt"],"additionalProperties":false,"description":"An import of a Confluence space."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0001","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0002","importer":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0003","name":"Alex Admin"},"source":"confluence-xml","state":"running","draftStep":3,"file":{"kind":"upload","name":"export.zip","size":1048576,"uploadId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0004","complete":true},"spaceName":"IT Operations","spaceKey":"ITOPS","archived":false,"sourceUrl":"https://example.atlassian.net/wiki","reviewers":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0005","name":"Robin Reviewer"}],"phase":"lineage","progress":{"done":0,"total":0},"found":{"pages":120,"blogPosts":6,"versions":340,"comments":85,"likes":30,"watchers":44,"attachments":40,"attachmentBytes":2048000,"people":12,"macroKinds":6,"spaceKey":"ITOPS","spaceName":"IT Operations"},"sourceSpaces":null,"history":false,"peopleSource":{"kind":"token","site":"example.atlassian.net","email":"alex@example.com","people":12,"withEmail":10},"connection":null,"files":[],"options":{},"throttledUntil":null,"waitingFor":null,"tokenDeletedAt":null,"counts":{"pages":120,"blogPosts":6,"attachments":40,"attachmentVersions":52,"comments":85,"people":12,"problems":7},"errorCode":null,"quarantineSpace":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0006","key":"ITOPS"},"targetSpace":null,"reimportSpaceId":null,"canManage":true,"canResolve":true,"canTakeOver":false,"startedAt":"2026-10-10T08:00:00.000Z","finishedAt":"2026-10-10T08:05:00.000Z","decidedAt":null,"fileExpiresAt":null,"createdAt":"2026-10-10T07:50:00.000Z","updatedAt":"2026-10-10T08:05:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`reimportNotInReview`: The changes do not wait to be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"reimportNotInReview":{"value":{"type":"urn:lunedo:problem:reimportNotInReview","title":"The changes do not wait to be applied","status":409,"code":"reimportNotInReview"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/imports/{importId}/changes":{"get":{"operationId":"imports.changes","summary":"List the changes of a re-import","description":"Lists the changes of one group. Nothing changes until the changes are applied. Changes of pages the caller cannot read are left out.\n\nRequires the permission `import.view` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.view","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}},{"name":"tab","in":"query","required":true,"description":"Group of changes to list.","schema":{"type":"string","enum":["conflicts","updates","deleted","moved","permissions"]}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"A page of changes.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the change."},"kind":{"type":"string","description":"What changed: a page, template, comment, attachment, space permission or page restriction. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","template","comment","attachment","spacePermission","restriction"]},"change":{"type":"string","description":"Kind of change: `new`, `updated`, `conflict`, `deleted` (deleted at the source), `moved` (follows the source), `movedHere` (moved in Lunedo, so it stays), `labels`, `gone` (a comment or attachment deleted at the source, only listed) or `permission`. New values can be added in later versions; handle unknown values.","x-extensible-enum":["new","updated","conflict","deleted","moved","movedHere","labels","gone","permission"]},"item":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the page."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the page in the addresses of the app."},"title":{"type":"string","description":"Title of the page in Lunedo."},"spaceKey":{"type":"string","description":"Key of its space."}},"required":["id","number","title","spaceKey"],"additionalProperties":false},{"type":"null"}],"description":"The page in Lunedo, or null when the change concerns something else."},"title":{"description":"Title of what changed.","type":["string","null"]},"sourceTitle":{"description":"Title at the source, for changed pages. Null for a change that waits for a restriction when the caller would lose access once it is applied.","type":["string","null"]},"reason":{"anyOf":[{"type":"string","x-extensible-enum":["both","editing","restricted"]},{"type":"null"}],"description":"Why it is a conflict: `both` when it was changed on both sides, `editing` when someone is editing the page, `restricted` when the page or a page above it was restricted further at the source and that permission difference is not applied yet. New values can be added in later versions; handle unknown values."},"editing":{"type":"boolean","description":"Whether someone was editing the page. Its source version is applied once the editing session has ended."},"changedHere":{"anyOf":[{"type":"object","properties":{"by":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when unknown.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who changed it last, or null when unknown."},"at":{"type":"string","format":"date-time","description":"When it was changed last in Lunedo. ISO 8601 timestamp in UTC."}},"required":["by","at"],"additionalProperties":false},{"type":"null"}],"description":"The last change in Lunedo, for conflicts."},"changedAtSource":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When it was changed at the source. ISO 8601 timestamp in UTC."},"from":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the page."},"title":{"type":"string","description":"Title of the page."}},"required":["id","title"],"additionalProperties":false,"description":"A page."},{"type":"null"}],"description":"Parent page before the move at the source, when the caller can see it."},"to":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the page."},"title":{"type":"string","description":"Title of the page."}},"required":["id","title"],"additionalProperties":false,"description":"A page."},{"type":"null"}],"description":"Parent page after the move at the source, when the caller can see it."},"labels":{"anyOf":[{"type":"object","properties":{"added":{"type":"array","items":{"type":"string"},"description":"Labels added at the source."},"removed":{"type":"array","items":{"type":"string"},"description":"Labels removed at the source. They are removed only if nobody touched them in Lunedo."}},"required":["added","removed"],"additionalProperties":false},{"type":"null"}],"description":"Label changes."},"permission":{"anyOf":[{"type":"object","properties":{"scope":{"type":"string","description":"Whether it concerns the space or a page restriction. New values can be added in later versions; handle unknown values.","x-extensible-enum":["space","page"]},"action":{"type":"string","description":"What applying does. New values can be added in later versions; handle unknown values.","x-extensible-enum":["grant","change","remove","restrict","unrestrict","listHolder","unlistHolder"]},"holder":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Kind of holder. New values can be added in later versions; handle unknown values.","x-extensible-enum":["account","group","organizationMembers"]},"id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the account or group in Lunedo."},"name":{"description":"Name in Lunedo, or null when unknown.","type":["string","null"]},"sourceName":{"description":"Name or ID at the source.","type":["string","null"]}},"required":["kind","id","name","sourceName"],"additionalProperties":false},{"type":"null"}],"description":"Who gains or loses the permission."},"role":{"description":"Role according to the source, or null when the role is removed.","type":["string","null"]},"currentRole":{"description":"Role in Lunedo now, or null.","type":["string","null"]},"restriction":{"description":"`view` or `edit` for page restrictions.","type":["string","null"]},"applicable":{"type":"boolean","description":"Whether it can be applied now. Holders not in Lunedo yet are mapped in the report first."}},"required":["scope","action","holder","role","currentRole","restriction","applicable"],"additionalProperties":false},{"type":"null"}],"description":"A difference to the permissions at the source. Lunedo never changes permissions by itself."},"held":{"type":"boolean","description":"Whether the change waits because the page or a page above it was restricted further at the source and that permission difference is not applied yet. Until then no source content of the page is stored."},"heldFor":{"anyOf":[{"type":"object","properties":{"differenceId":{"type":"string","format":"uuid","description":"ID of the permission difference to apply first."},"title":{"type":"string","description":"Title of the page the difference restricts."}},"required":["differenceId","title"],"additionalProperties":false},{"type":"null"}],"description":"The permission difference the change waits for, when the caller can see its page."},"decisions":{"type":"array","items":{"type":"string","description":"Decision: for a conflict `lunedo` keeps the Lunedo version, `source` takes the source version as a new version, `both` keeps the Lunedo version and adds the source version to the history, marked as not applied; for a page deleted at the source `trash` moves it to the trash and `keep` keeps it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["lunedo","source","both","trash","keep"]},"description":"Decisions that can be taken now. While a conflict waits for a restriction, only `lunedo` is possible."},"decision":{"anyOf":[{"type":"string","x-extensible-enum":["lunedo","source","both","trash","keep"]},{"type":"null"}],"description":"Decision: for a conflict `lunedo` keeps the Lunedo version, `source` takes the source version as a new version, `both` keeps the Lunedo version and adds the source version to the history, marked as not applied; for a page deleted at the source `trash` moves it to the trash and `keep` keeps it. New values can be added in later versions; handle unknown values."},"decidedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when unknown.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who decided, or null."},"decidedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When it was decided. ISO 8601 timestamp in UTC."},"appliedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When it was applied, or null while it waits. ISO 8601 timestamp in UTC."}},"required":["id","kind","change","item","title","sourceTitle","reason","editing","changedHere","changedAtSource","from","to","labels","permission","held","heldFor","decisions","decision","decidedBy","decidedAt","appliedAt"],"additionalProperties":false,"description":"A change found by a re-import."},"description":"Changes, oldest first."},"nextCursor":{"description":"Cursor of the next page, or null.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"A page of changes."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0101","kind":"page","change":"conflict","item":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0102","number":1042,"title":"On-call rota","spaceKey":"ITOPS"},"title":"On-call rota","sourceTitle":"On-call rota","reason":"both","editing":false,"changedHere":{"by":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0103","name":"Lukas Hofer"},"at":"2026-10-09T09:00:00.000Z"},"changedAtSource":"2026-10-10T08:00:00.000Z","from":null,"to":null,"labels":null,"permission":null,"held":false,"heldFor":null,"decisions":["lunedo","source","both"],"decision":null,"decidedBy":null,"decidedAt":null,"appliedAt":null}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`changesUnavailable`: The changes are not listed yet.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"changesUnavailable":{"value":{"type":"urn:lunedo:problem:changesUnavailable","title":"The changes are not listed yet","status":409,"code":"changesUnavailable"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/imports/{importId}/changes/{changeId}/apply":{"post":{"operationId":"imports.applyDifference","summary":"Apply a permission difference","description":"Applies one difference to the permissions at the source and records it in the audit log. Show its effect with the preview first.\n\nRequires the permission `import.resolve` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.resolve","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}},{"name":"changeId","in":"path","required":true,"description":"ID of the change.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`changeNotFound`: The change does not exist. `notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"changeNotFound":{"value":{"type":"urn:lunedo:problem:changeNotFound","title":"The change does not exist","status":404,"code":"changeNotFound"}},"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`differenceResolved`: The difference no longer exists. `holderNotInLunedo`: The person or group is not in Lunedo yet. `lastSpaceAdmin`: A space needs at least one space admin. `notRestricted`: The page has no restriction of this kind. `reimportNotInReview`: The changes do not wait to be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"differenceResolved":{"value":{"type":"urn:lunedo:problem:differenceResolved","title":"The difference no longer exists","status":409,"code":"differenceResolved"}},"holderNotInLunedo":{"value":{"type":"urn:lunedo:problem:holderNotInLunedo","title":"The person or group is not in Lunedo yet","status":409,"code":"holderNotInLunedo"}},"lastSpaceAdmin":{"value":{"type":"urn:lunedo:problem:lastSpaceAdmin","title":"A space needs at least one space admin","status":409,"code":"lastSpaceAdmin"}},"notRestricted":{"value":{"type":"urn:lunedo:problem:notRestricted","title":"The page has no restriction of this kind","status":409,"code":"notRestricted"}},"reimportNotInReview":{"value":{"type":"urn:lunedo:problem:reimportNotInReview","title":"The changes do not wait to be applied","status":409,"code":"reimportNotInReview"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/imports/{importId}/changes/{changeId}/compare":{"get":{"operationId":"imports.compareChange","summary":"Compare a conflict","description":"Compares the current content of a page or space template in Lunedo with the content of the new export, converted as it would be applied, without applying anything. The Lunedo side is the draft for people who may edit the page, otherwise its latest version. The source of a page restricted further at the source is shown only to people who keep access once the restriction is applied.\n\nRequires the permission `import.view` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.view","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}},{"name":"changeId","in":"path","required":true,"description":"ID of the change.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The comparison.","content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","description":"Whether a page or a space template is compared. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","template"]},"lunedo":{"type":"object","properties":{"title":{"type":"string","description":"Title on this side."},"version":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Version number: in Lunedo the published version when the caller may only read the page, null for the current draft or a template; at the source the version in the export."}},"required":["title","version"],"additionalProperties":false,"description":"The current content in Lunedo."},"source":{"type":"object","properties":{"title":{"type":"string","description":"Title on this side."},"version":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Version number: in Lunedo the published version when the caller may only read the page, null for the current draft or a template; at the source the version in the export."}},"required":["title","version"],"additionalProperties":false,"description":"The content of the new export, converted as it would be applied."},"decisions":{"type":"array","items":{"type":"string","description":"Decision: for a conflict `lunedo` keeps the Lunedo version, `source` takes the source version as a new version, `both` keeps the Lunedo version and adds the source version to the history, marked as not applied; for a page deleted at the source `trash` moves it to the trash and `keep` keeps it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["lunedo","source","both","trash","keep"]},"description":"Decisions that can be taken now. While the page waits for a restriction from the source, only `lunedo` is possible."},"decision":{"anyOf":[{"type":"string","description":"Decision: for a conflict `lunedo` keeps the Lunedo version, `source` takes the source version as a new version, `both` keeps the Lunedo version and adds the source version to the history, marked as not applied; for a page deleted at the source `trash` moves it to the trash and `keep` keeps it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["lunedo","source","both","trash","keep"]},{"type":"null"}],"description":"The decision taken for the conflict so far, or null."},"diff":{"description":"The comparison in the same form as the comparison of two versions: `title`, `blocks` and the number of `changes`.","$ref":"#/components/schemas/Schema113ae44d8375"},"before":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schemafbc378f59d82"},"after":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schemafbc378f59d82"},"references":{"type":"object","properties":{"people":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","description":"Name of the person."},"description":"Names of mentioned people the caller may see, by account ID."},"pictures":{"description":"Profile pictures of the people in `people` that have one, by account ID. The picture is at `/api/v1/accounts/{accountId}/picture`.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","description":"Version of the profile picture."}},"pages":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"title":{"type":"string","description":"Title, or empty without access."},"spaceKey":{"type":"string","description":"Key of the page's space, or empty without access."},"kind":{"type":"string","description":"Kind of the item."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the item in the addresses of the app, or null without access."},"accessible":{"type":"boolean","description":"Whether the caller can open the page."},"inTrash":{"type":"boolean","description":"Whether the page is in the trash. Then only the title is given, as `In trash`."}},"required":["title","spaceKey","kind","number","accessible","inTrash"],"additionalProperties":false,"description":"A linked page."},"description":"Linked pages by ID."},"topics":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"title":{"type":"string","description":"Title of the running topic."},"status":{"type":"string","description":"Whether the topic is still open. New values can be added in later versions; handle unknown values.","x-extensible-enum":["open","closed"]}},"required":["title","status"],"additionalProperties":false,"description":"A running topic."},"description":"Running topics that topic updates and decisions in the document refer to, by ID, as far as the caller may see them."},"tooLargeImages":{"type":"array","items":{"type":"string","format":"uuid","description":"ID of an attachment."},"description":"Images in the document with more than 100 megapixels, as far as the caller may see them. They have no smaller version and are shown as a file that opens in full size."}},"required":["people","pages","topics","tooLargeImages"],"additionalProperties":false,"description":"What mentions and page links in the document point to, as far as the caller may see it."}},"required":["kind","lunedo","source","decisions","decision","diff","before","after","references"],"additionalProperties":false,"description":"The current content in Lunedo compared with the content of the new export. Nothing is applied."},"example":{"kind":"page","lunedo":{"title":"Release plan","version":null},"source":{"title":"Release plan","version":7},"decisions":["lunedo","source","both"],"decision":null,"diff":{"title":null,"blocks":[],"changes":0},"before":{"type":"doc","content":[]},"after":{"type":"doc","content":[]},"references":{"people":{},"pages":{},"topics":{},"tooLargeImages":[]}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`comparisonWithheld`: The new content is restricted at the source. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"comparisonWithheld":{"value":{"type":"urn:lunedo:problem:comparisonWithheld","title":"The new content is restricted at the source","status":403,"code":"comparisonWithheld"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`changeNotFound`: The change does not exist. `notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"changeNotFound":{"value":{"type":"urn:lunedo:problem:changeNotFound","title":"The change does not exist","status":404,"code":"changeNotFound"}},"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`changeNotComparable`: Only conflicts can be compared. `changesUnavailable`: The changes are not listed yet. `comparisonUnavailable`: The comparison is no longer available.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"changeNotComparable":{"value":{"type":"urn:lunedo:problem:changeNotComparable","title":"Only conflicts can be compared","status":409,"code":"changeNotComparable"}},"changesUnavailable":{"value":{"type":"urn:lunedo:problem:changesUnavailable","title":"The changes are not listed yet","status":409,"code":"changesUnavailable"}},"comparisonUnavailable":{"value":{"type":"urn:lunedo:problem:comparisonUnavailable","title":"The comparison is no longer available","status":409,"code":"comparisonUnavailable"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/imports/{importId}/changes/{changeId}/preview":{"post":{"operationId":"imports.previewDifference","summary":"Preview a permission difference","description":"Shows who gains or loses access when the permission difference is applied. Space differences need permission to manage the space, page differences permission to share the page.\n\nRequires the permission `import.resolve` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.resolve","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}},{"name":"changeId","in":"path","required":true,"description":"ID of the change.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Who gains or loses access.","content":{"application/json":{"schema":{"type":"object","properties":{"space":{"anyOf":[{"type":"object","properties":{"gaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who get access."},"losing":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who lose access."},"raised":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role rises."},"lowered":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role drops."},"unlisted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of affected people the caller may not see; they are counted but not listed."},"truncated":{"type":"boolean","description":"Whether `changes` lists only the first 100 people."},"changes":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."},"before":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role before the change, or null for no access."},"after":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role after the change, or null for no access."}},"required":["accountId","name","before","after"],"additionalProperties":false,"description":"How the access of one person changes."},"description":"People whose access changes, ordered by name."}},"required":["gaining","losing","raised","lowered","unlisted","truncated","changes"],"additionalProperties":false,"description":"Who gains, loses or changes access."},{"type":"null"}],"description":"Effect on the space, for space differences."},"page":{"anyOf":[{"type":"object","properties":{"read":{"type":"object","properties":{"gaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who get access."},"losing":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who lose access."},"raised":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role rises."},"lowered":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role drops."},"unlisted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of affected people the caller may not see; they are counted but not listed."},"truncated":{"type":"boolean","description":"Whether `changes` lists only the first 100 people."},"changes":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."},"before":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role before the change, or null for no access."},"after":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role after the change, or null for no access."}},"required":["accountId","name","before","after"],"additionalProperties":false,"description":"How the access of one person changes."},"description":"People whose access changes, ordered by name."}},"required":["gaining","losing","raised","lowered","unlisted","truncated","changes"],"additionalProperties":false,"description":"Who gains or loses the right to read."},"edit":{"type":"object","properties":{"gaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who get access."},"losing":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who lose access."},"raised":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role rises."},"lowered":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role drops."},"unlisted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of affected people the caller may not see; they are counted but not listed."},"truncated":{"type":"boolean","description":"Whether `changes` lists only the first 100 people."},"changes":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."},"before":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role before the change, or null for no access."},"after":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role after the change, or null for no access."}},"required":["accountId","name","before","after"],"additionalProperties":false,"description":"How the access of one person changes."},"description":"People whose access changes, ordered by name."}},"required":["gaining","losing","raised","lowered","unlisted","truncated","changes"],"additionalProperties":false,"description":"Who gains or loses the right to edit."}},"required":["read","edit"],"additionalProperties":false,"description":"How access to the page would change."},{"type":"null"}],"description":"Effect on reading and editing the page, for page differences."}},"required":["space","page"],"additionalProperties":false,"description":"Who gains or loses access when a permission difference is applied."},"example":{"space":{"gaining":3,"losing":0,"raised":0,"lowered":0,"changes":[],"unlisted":3,"truncated":false},"page":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`changeNotFound`: The change does not exist. `notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"changeNotFound":{"value":{"type":"urn:lunedo:problem:changeNotFound","title":"The change does not exist","status":404,"code":"changeNotFound"}},"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`changeApplied`: The change was applied already. `holderNotInLunedo`: The person or group is not in Lunedo yet. `reimportNotInReview`: The changes do not wait to be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"changeApplied":{"value":{"type":"urn:lunedo:problem:changeApplied","title":"The change was applied already","status":409,"code":"changeApplied"}},"holderNotInLunedo":{"value":{"type":"urn:lunedo:problem:holderNotInLunedo","title":"The person or group is not in Lunedo yet","status":409,"code":"holderNotInLunedo"}},"reimportNotInReview":{"value":{"type":"urn:lunedo:problem:reimportNotInReview","title":"The changes do not wait to be applied","status":409,"code":"reimportNotInReview"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/imports/{importId}/changes/decisions":{"put":{"operationId":"imports.decide","summary":"Decide changes of a re-import","description":"Records one decision for up to 500 conflicts or pages deleted at the source. Nothing changes until the changes are applied; a decision can be taken back until then. While a conflict waits for a restriction applied at the source, only `lunedo` is accepted for it.\n\nRequires the permission `import.resolve` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.resolve","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"minItems":1,"maxItems":500,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a change."},"description":"The changes to decide, up to 500 at once."},"decision":{"anyOf":[{"type":"string","description":"Decision: for a conflict `lunedo` keeps the Lunedo version, `source` takes the source version as a new version, `both` keeps the Lunedo version and adds the source version to the history, marked as not applied; for a page deleted at the source `trash` moves it to the trash and `keep` keeps it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["lunedo","source","both","trash","keep"]},{"type":"null"}],"description":"The decision, or null to take it back."}},"required":["ids","decision"],"additionalProperties":false,"description":"A decision for one or more changes."},"example":{"ids":["01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0101"],"decision":"lunedo"}}}},"responses":{"200":{"description":"How many changes were decided.","content":{"application/json":{"schema":{"type":"object","properties":{"decided":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of changes decided."}},"required":["decided"],"additionalProperties":false,"description":"Result of a decision."},"example":{"decided":1}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidDecision`: The decision does not fit the change. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidDecision":{"value":{"type":"urn:lunedo:problem:invalidDecision","title":"The decision does not fit the change","status":400,"code":"invalidDecision"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`changeNotFound`: The change does not exist. `notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"changeNotFound":{"value":{"type":"urn:lunedo:problem:changeNotFound","title":"The change does not exist","status":404,"code":"changeNotFound"}},"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`changeApplied`: The change was applied already. `reimportNotInReview`: The changes do not wait to be applied. `restrictionPending`: The restriction from the source is not applied yet.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"changeApplied":{"value":{"type":"urn:lunedo:problem:changeApplied","title":"The change was applied already","status":409,"code":"changeApplied"}},"reimportNotInReview":{"value":{"type":"urn:lunedo:problem:reimportNotInReview","title":"The changes do not wait to be applied","status":409,"code":"reimportNotInReview"}},"restrictionPending":{"value":{"type":"urn:lunedo:problem:restrictionPending","title":"The restriction from the source is not applied yet","status":409,"code":"restrictionPending"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/imports/{importId}/changes/summary":{"get":{"operationId":"imports.changeSummary","summary":"Summarize the changes of a re-import","description":"Counts the changes a re-import found, by group, with the conflicts and deletions that still wait for a decision. Changes of pages the caller cannot read are only counted as hidden.\n\nRequires the permission `import.view` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.view","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The summary.","content":{"application/json":{"schema":{"type":"object","properties":{"tabs":{"type":"array","items":{"type":"object","properties":{"tab":{"type":"string","description":"Group of changes: `conflicts` (changed in Lunedo and at the source, or held because someone is editing), `updates` (new and changed only at the source), `deleted` (deleted at the source), `moved` (moved at the source) and `permissions` (differences to the permissions in the source). New values can be added in later versions; handle unknown values.","x-extensible-enum":["conflicts","updates","deleted","moved","permissions"]},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Changes in this group the caller can see."},"open":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Of these, changes that still need a decision."}},"required":["tab","count","open"],"additionalProperties":false,"description":"A group of changes."},"description":"Changes by group."},"hidden":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Changes of pages the caller cannot read. They are decided by someone with access."},"counts":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"What the comparison found: `new`, `updated`, `unchanged`, `conflicts`, `deleted`, `moved`, `movedHere`, `labels`, `deletedHere`, `newComments`, `goneComments`, `newAttachmentVersions`, `goneAttachments`, `newTemplates`, `updatedTemplates`, `permissions` and `restricted` (new pages and label changes that wait until a restriction of a page above them is applied)."},"open":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Conflicts and deletions that still wait, including those the caller cannot see."},"applying":{"type":"boolean","description":"Whether Lunedo is applying the changes right now."}},"required":["tabs","hidden","counts","open","applying"],"additionalProperties":false,"description":"Summary of the changes of a re-import."},"example":{"tabs":[{"tab":"conflicts","count":4,"open":4},{"tab":"updates","count":31,"open":0},{"tab":"deleted","count":2,"open":2},{"tab":"moved","count":0,"open":0},{"tab":"permissions","count":1,"open":0}],"hidden":0,"counts":{"new":12,"updated":19,"unchanged":1203,"conflicts":4,"deleted":2},"open":6,"applying":false}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`changesUnavailable`: The changes are not listed yet.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"changesUnavailable":{"value":{"type":"urn:lunedo:problem:changesUnavailable","title":"The changes are not listed yet","status":409,"code":"changesUnavailable"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/imports/{importId}/connection":{"put":{"operationId":"imports.connection","summary":"Connect an import to Confluence","description":"Sets how an import of the source `confluence-cloud` or `confluence-dc` reads Confluence through its API. Lunedo tests the connection at once, stores the token encrypted, uses it only for this import and the imports of further spaces chosen with it, and deletes it when the last of them is accepted, discarded, stopped or fails, when the importer loses the permission to import, or when the draft is left alone for a week. Only `https` sites under `atlassian.net` or hosts the instance administrator allowed are contacted, never addresses in private networks unless the instance allows them, and redirects are not followed.\n\nRequires the permission `import.manage` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.manage","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"cloud","description":"Confluence Cloud."},"site":{"type":"string","maxLength":300,"description":"Address of the site, such as `example.atlassian.net`."},"email":{"type":"string","maxLength":320,"description":"E-mail address of the Atlassian account the token belongs to."},"token":{"type":"string","maxLength":1000,"description":"API token of that account. It is stored encrypted."}},"required":["kind","site","email","token"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"dataCenter","description":"Confluence Data Center or Server 7.9 or newer."},"baseUrl":{"type":"string","maxLength":500,"description":"Address Confluence is opened with, including a context path, such as `https://wiki.example.com/confluence`."},"token":{"type":"string","maxLength":1000,"description":"Personal access token. It is stored encrypted."},"caCertificates":{"description":"Certificates of the authority that issued the server certificate, in PEM format, when it is not publicly trusted.","anyOf":[{"type":"string","maxLength":100000},{"type":"null"}]}},"required":["kind","baseUrl","token"],"additionalProperties":false}],"description":"How Lunedo reads Confluence through its API."},"example":{"kind":"cloud","site":"example.atlassian.net","email":"alex@example.com","token":"ATATT3x…"}}}},"responses":{"200":{"description":"The import.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the import."},"organizationId":{"type":"string","format":"uuid","description":"Organization the import belongs to."},"importer":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"The administrator who imports."},"source":{"type":"string","description":"What is imported: `confluence-xml` for the XML space export of Confluence Cloud or Data Center, `confluence-csv` for the CSV space export of Confluence Cloud, `confluence-cloud` and `confluence-dc` to read a space through the Confluence API, `markdown` for a ZIP file of Markdown files, `word` for Word documents (`.docx`). New values can be added in later versions; handle unknown values.","x-extensible-enum":["confluence-xml","confluence-csv","confluence-cloud","confluence-dc","markdown","word"]},"state":{"type":"string","description":"State of the import. `draft` while the wizard is filled in, `analyzing` while the export is read, `ready` when it can be started, `running` while it imports, `held` when the importing administrator lost the permission and another administrator has to take over, `stopping` and `discarding` while the quarantine space is deleted, `review` when the quarantine space waits for a decision, `accepted`, `discarded`, `stopped` and `failed` at the end. A re-import is in `running` while it compares or applies, in `review` while changes wait for a decision, `accepted` when everything is applied, and `superseded` when a newer re-import of the same space replaced it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["draft","analyzing","ready","running","held","stopping","review","accepting","accepted","discarding","discarded","stopped","failed","superseded"]},"draftStep":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Step of the wizard the importer was on, for continuing a draft."},"file":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Where the export comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload","folder"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes, or null when not known yet."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload, or null for a file in the import folder."},"complete":{"type":"boolean","description":"Whether the file is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},{"type":"null"}],"description":"The export file, or null when none is chosen yet."},"spaceName":{"description":"Name of the new space.","type":["string","null"]},"spaceKey":{"description":"Key of the new space.","type":["string","null"]},"archived":{"type":"boolean","description":"Whether the space becomes archived when the import is accepted."},"history":{"type":"boolean","description":"Whether every Confluence version becomes a Lunedo version, or only the current state is imported."},"peopleSource":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"How people are recognized: `token` reads names and e-mail addresses with a read-only Atlassian API token, `list` uses a user list exported from the Atlassian administration, `skip` keeps every author as a placeholder, `source` takes the names Confluence Data Center returns through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["token","list","skip","source"]},"site":{"description":"Confluence site the token is used with, or null.","type":["string","null"]},"email":{"description":"Atlassian e-mail address the token belongs to, or null.","type":["string","null"]},"people":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"People of the export the token could read, or people in the user list; null when unknown."},"withEmail":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Of these, people with a visible e-mail address."}},"required":["kind","site","email","people","withEmail"],"additionalProperties":false},{"type":"null"}],"description":"How people are recognized. The token itself is never returned."},"connection":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Kind of Confluence the import reads through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["cloud","dataCenter"]},"site":{"type":"string","description":"Host name of the Confluence site, with the port when it is not 443."},"basePath":{"type":"string","description":"Context path of Confluence Data Center, such as `/confluence`, or empty."},"email":{"description":"Atlassian e-mail address the API token belongs to, or null.","type":["string","null"]},"account":{"description":"Name of the Confluence account the token belongs to.","type":["string","null"]},"selection":{"type":"array","items":{"type":"object","properties":{"importId":{"type":"string","format":"uuid","description":"ID of the import that reads the space."},"spaceKey":{"type":"string","description":"Key of the Confluence space."}},"required":["importId","spaceKey"],"additionalProperties":false},"description":"Spaces chosen with this connection whose imports are not started yet, one import per space, this import included. Empty once the import has started."}},"required":["kind","site","basePath","email","account","selection"],"additionalProperties":false},{"type":"null"}],"description":"The connection of an import through the Confluence API, or null. Several imports of the same importer can share one connection; the token is never returned."},"files":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","description":"Where the document comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload."},"complete":{"type":"boolean","description":"Whether the upload is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},"description":"The Word documents of a `word` import, in their order. Empty for other imports."},"options":{"type":"object","properties":{"spaceKey":{"description":"Key of the Confluence space read through the API or from a site backup.","type":"string"},"pageIds":{"description":"IDs of the top-level pages whose trees are imported; all pages when left out.","type":"array","items":{"type":"string"}},"blogPosts":{"description":"Whether blog posts are imported; true when left out.","type":"boolean"},"split":{"type":"string","description":"`file` makes each Word document one page, `heading` adds a subpage per top-level heading. New values can be added in later versions; handle unknown values.","x-extensible-enum":["file","heading"]},"knowledgeBase":{"description":"For a `markdown` import: whether the new space is a knowledge base.","type":"boolean"}},"additionalProperties":false,"description":"Options of the source."},"throttledUntil":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Until when Confluence asked Lunedo to slow down, or null. The import continues by itself. ISO 8601 timestamp in UTC."},"waitingFor":{"description":"Key of the Confluence space whose import over the same connection reads or runs first, or null. Imports sharing a connection run one after another; this one continues by itself.","type":["string","null"]},"tokenDeletedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the API token was deleted: when the import was accepted, discarded, stopped or failed, when the importer lost the permission to import, or when the draft was left alone for a week. ISO 8601 timestamp in UTC."},"sourceUrl":{"description":"Address of the Confluence site. Links to pages outside the export point there.","type":["string","null"]},"reviewers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"People who can read the quarantine space and the report."},"phase":{"anyOf":[{"type":"string","x-extensible-enum":["read","compare","space","people","pages","attachments","templates","content","comments","reactions","permissions","baseline","finish","lineage","moves","labels","deletions","done"]},{"type":"null"}],"description":"Step the import is in: `read` reads the export, then `space`, `people`, `pages`, `attachments`, `templates`, `content`, `comments`, `reactions`, `permissions`, `baseline` and `finish`; `done` after the last step. A re-import compares in `compare` and applies in `lineage`, `people`, `pages`, `moves`, `attachments`, `templates`, `content`, `labels`, `comments`, `reactions`, `deletions`, `baseline` and `finish`. New values can be added in later versions; handle unknown values."},"progress":{"type":"object","properties":{"done":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units done in the current step."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units of the current step, or 0 when not known."}},"required":["done","total"],"additionalProperties":false,"description":"Progress of the current step."},"found":{"anyOf":[{"type":"object","properties":{"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages in the export."},"blogPosts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Blog posts in the export."},"versions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Earlier versions of pages and blog posts."},"comments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Comments, including inline comments and replies."},"likes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Likes on pages, blog posts and comments."},"watchers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Watchers of pages and the space. They are counted, not imported."},"attachments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Attachments of these pages."},"attachmentBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the current attachment versions in bytes."},"people":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"People named in the export."},"macroKinds":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Different macros used on the pages."},"spaceKey":{"type":"string","description":"Key of the space in Confluence."},"spaceName":{"type":"string","description":"Name of the space in Confluence."}},"required":["pages","blogPosts","versions","comments","likes","watchers","attachments","attachmentBytes","people","macroKinds","spaceKey","spaceName"],"additionalProperties":false},{"type":"null"}],"description":"What the export contains, once it was read."},"sourceSpaces":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the space in Confluence."},"name":{"type":"string","description":"Name of the space in Confluence."}},"required":["key","name"],"additionalProperties":false}},{"type":"null"}],"description":"The spaces of a site backup, once it was read; choose one with `options.spaceKey`. Null for exports and backups of one space."},"counts":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"What was imported, by kind: `pages`, `blogPosts`, `versions`, `attachments`, `attachmentVersions`, `comments`, `inlineAnchored`, `inlineMoved`, `likes`, `watchers`, `people`, `peopleMatched`, `restrictions`, `groupsMissing` and `problems`."},"errorCode":{"description":"Why the export could not be read or the import failed, such as `notAnArchive`, `wrongFormat`, `archiveTooLarge`, `unsafeEntryName`, `xmlDeclaration`, `spaceChoiceRequired` (a site backup with several spaces; see `sourceSpaces`) or `internalError`.","type":["string","null"]},"quarantineSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."}},"required":["id","key"],"additionalProperties":false},{"type":"null"}],"description":"The space the import writes into."},"targetSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"name":{"type":"string","description":"Name of the space."}},"required":["id","key","name"],"additionalProperties":false},{"type":"null"}],"description":"For a re-import, the space created by the earlier import that the changes go into; otherwise null."},"reimportSpaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space a newer export of the same Confluence space can be imported into again, or null when this import offers no re-import."},"canManage":{"type":"boolean","description":"Whether the caller can change, start, stop, accept or discard the import."},"canResolve":{"type":"boolean","description":"Whether the caller can map people and groups of the import or apply a user list."},"canTakeOver":{"type":"boolean","description":"Whether the caller can take over a held import."},"startedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import finished or failed. ISO 8601 timestamp in UTC."},"decidedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import was accepted, discarded or stopped. ISO 8601 timestamp in UTC."},"fileExpiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When an uploaded file is deleted. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the import was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the import last changed. ISO 8601 timestamp in UTC."}},"required":["id","organizationId","importer","source","state","draftStep","file","spaceName","spaceKey","archived","history","peopleSource","connection","files","options","throttledUntil","waitingFor","tokenDeletedAt","sourceUrl","reviewers","phase","progress","found","sourceSpaces","counts","errorCode","quarantineSpace","targetSpace","reimportSpaceId","canManage","canResolve","canTakeOver","startedAt","finishedAt","decidedAt","fileExpiresAt","createdAt","updatedAt"],"additionalProperties":false,"description":"An import of a Confluence space."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0001","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0002","importer":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0003","name":"Alex Admin"},"source":"confluence-xml","state":"review","draftStep":3,"file":{"kind":"upload","name":"export.zip","size":1048576,"uploadId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0004","complete":true},"spaceName":"IT Operations","spaceKey":"ITOPS","archived":false,"sourceUrl":"https://example.atlassian.net/wiki","reviewers":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0005","name":"Robin Reviewer"}],"phase":null,"progress":{"done":0,"total":0},"found":{"pages":120,"blogPosts":6,"versions":340,"comments":85,"likes":30,"watchers":44,"attachments":40,"attachmentBytes":2048000,"people":12,"macroKinds":6,"spaceKey":"ITOPS","spaceName":"IT Operations"},"sourceSpaces":null,"history":false,"peopleSource":{"kind":"token","site":"example.atlassian.net","email":"alex@example.com","people":12,"withEmail":10},"connection":null,"files":[],"options":{},"throttledUntil":null,"waitingFor":null,"tokenDeletedAt":null,"counts":{"pages":120,"blogPosts":6,"attachments":40,"attachmentVersions":52,"comments":85,"people":12,"problems":7},"errorCode":null,"quarantineSpace":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0006","key":"ITOPS"},"targetSpace":null,"reimportSpaceId":null,"canManage":true,"canResolve":true,"canTakeOver":false,"startedAt":"2026-10-10T08:00:00.000Z","finishedAt":"2026-10-10T08:05:00.000Z","decidedAt":null,"fileExpiresAt":null,"createdAt":"2026-10-10T07:50:00.000Z","updatedAt":"2026-10-10T08:05:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `confluenceBlocked`: Lunedo may not connect to this address. `confluenceUnauthorized`: Confluence refused the token. `invalidAccessToken`: The personal access token is not valid. `invalidAtlassianEmail`: The Atlassian e-mail address is not valid. `invalidAtlassianSite`: The Atlassian site is not allowed. `invalidAtlassianToken`: The Atlassian API token is not valid. `invalidCertificate`: The certificate cannot be used. `invalidDataCenterAddress`: The Confluence Data Center address is not allowed. `invalidInput`: The request is not valid. `wrongInput`: This kind of import does not take this input.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"confluenceBlocked":{"value":{"type":"urn:lunedo:problem:confluenceBlocked","title":"Lunedo may not connect to this address","status":400,"code":"confluenceBlocked"}},"confluenceUnauthorized":{"value":{"type":"urn:lunedo:problem:confluenceUnauthorized","title":"Confluence refused the token","status":400,"code":"confluenceUnauthorized"}},"invalidAccessToken":{"value":{"type":"urn:lunedo:problem:invalidAccessToken","title":"The personal access token is not valid","status":400,"code":"invalidAccessToken"}},"invalidAtlassianEmail":{"value":{"type":"urn:lunedo:problem:invalidAtlassianEmail","title":"The Atlassian e-mail address is not valid","status":400,"code":"invalidAtlassianEmail"}},"invalidAtlassianSite":{"value":{"type":"urn:lunedo:problem:invalidAtlassianSite","title":"The Atlassian site is not allowed","status":400,"code":"invalidAtlassianSite"}},"invalidAtlassianToken":{"value":{"type":"urn:lunedo:problem:invalidAtlassianToken","title":"The Atlassian API token is not valid","status":400,"code":"invalidAtlassianToken"}},"invalidCertificate":{"value":{"type":"urn:lunedo:problem:invalidCertificate","title":"The certificate cannot be used","status":400,"code":"invalidCertificate"}},"invalidDataCenterAddress":{"value":{"type":"urn:lunedo:problem:invalidDataCenterAddress","title":"The Confluence Data Center address is not allowed","status":400,"code":"invalidDataCenterAddress"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"wrongInput":{"value":{"type":"urn:lunedo:problem:wrongInput","title":"This kind of import does not take this input","status":400,"code":"wrongInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`importStarted`: The import has started.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"importStarted":{"value":{"type":"urn:lunedo:problem:importStarted","title":"The import has started","status":409,"code":"importStarted"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"502":{"description":"`confluenceCertificate`: The certificate of Confluence is not trusted. `confluenceInvalidResponse`: Confluence sent an answer Lunedo cannot read. `confluenceRedirect`: Confluence redirected to another address. `confluenceUnreachable`: Confluence could not be reached.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"confluenceCertificate":{"value":{"type":"urn:lunedo:problem:confluenceCertificate","title":"The certificate of Confluence is not trusted","status":502,"code":"confluenceCertificate"}},"confluenceInvalidResponse":{"value":{"type":"urn:lunedo:problem:confluenceInvalidResponse","title":"Confluence sent an answer Lunedo cannot read","status":502,"code":"confluenceInvalidResponse"}},"confluenceRedirect":{"value":{"type":"urn:lunedo:problem:confluenceRedirect","title":"Confluence redirected to another address","status":502,"code":"confluenceRedirect"}},"confluenceUnreachable":{"value":{"type":"urn:lunedo:problem:confluenceUnreachable","title":"Confluence could not be reached","status":502,"code":"confluenceUnreachable"}}}}}},"503":{"description":"`confluenceRateLimited`: Confluence asked to slow down. `maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"confluenceRateLimited":{"value":{"type":"urn:lunedo:problem:confluenceRateLimited","title":"Confluence asked to slow down","status":503,"code":"confluenceRateLimited"}},"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/imports/{importId}/connection/selection":{"put":{"operationId":"imports.selection","summary":"Choose the Confluence spaces to import","description":"Chooses one or more spaces of the connection of an import draft. Each space is imported on its own, into its own new space, with its own check, dry run, report and re-import. The import keeps its space when it is chosen; Lunedo creates a draft for every other space that shares the connection and its token, and removes the drafts of spaces no longer chosen. Imports sharing a connection read and run one after another. The shared token is deleted when the last of them has ended or been removed. A re-import reads only the space it came from.\n\nRequires the permission `import.manage` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.manage","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"spaceKeys":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"string","maxLength":255},"description":"Keys of the Confluence spaces to import, 1 to 50. The import keeps its space when it is in the list; every other space gets an import of its own over the same connection, and drafts of spaces no longer listed are removed."}},"required":["spaceKeys"],"additionalProperties":false,"description":"The Confluence spaces to import."},"example":{"spaceKeys":["ITOPS","HR"]}}}},"responses":{"200":{"description":"The import.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the import."},"organizationId":{"type":"string","format":"uuid","description":"Organization the import belongs to."},"importer":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"The administrator who imports."},"source":{"type":"string","description":"What is imported: `confluence-xml` for the XML space export of Confluence Cloud or Data Center, `confluence-csv` for the CSV space export of Confluence Cloud, `confluence-cloud` and `confluence-dc` to read a space through the Confluence API, `markdown` for a ZIP file of Markdown files, `word` for Word documents (`.docx`). New values can be added in later versions; handle unknown values.","x-extensible-enum":["confluence-xml","confluence-csv","confluence-cloud","confluence-dc","markdown","word"]},"state":{"type":"string","description":"State of the import. `draft` while the wizard is filled in, `analyzing` while the export is read, `ready` when it can be started, `running` while it imports, `held` when the importing administrator lost the permission and another administrator has to take over, `stopping` and `discarding` while the quarantine space is deleted, `review` when the quarantine space waits for a decision, `accepted`, `discarded`, `stopped` and `failed` at the end. A re-import is in `running` while it compares or applies, in `review` while changes wait for a decision, `accepted` when everything is applied, and `superseded` when a newer re-import of the same space replaced it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["draft","analyzing","ready","running","held","stopping","review","accepting","accepted","discarding","discarded","stopped","failed","superseded"]},"draftStep":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Step of the wizard the importer was on, for continuing a draft."},"file":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Where the export comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload","folder"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes, or null when not known yet."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload, or null for a file in the import folder."},"complete":{"type":"boolean","description":"Whether the file is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},{"type":"null"}],"description":"The export file, or null when none is chosen yet."},"spaceName":{"description":"Name of the new space.","type":["string","null"]},"spaceKey":{"description":"Key of the new space.","type":["string","null"]},"archived":{"type":"boolean","description":"Whether the space becomes archived when the import is accepted."},"history":{"type":"boolean","description":"Whether every Confluence version becomes a Lunedo version, or only the current state is imported."},"peopleSource":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"How people are recognized: `token` reads names and e-mail addresses with a read-only Atlassian API token, `list` uses a user list exported from the Atlassian administration, `skip` keeps every author as a placeholder, `source` takes the names Confluence Data Center returns through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["token","list","skip","source"]},"site":{"description":"Confluence site the token is used with, or null.","type":["string","null"]},"email":{"description":"Atlassian e-mail address the token belongs to, or null.","type":["string","null"]},"people":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"People of the export the token could read, or people in the user list; null when unknown."},"withEmail":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Of these, people with a visible e-mail address."}},"required":["kind","site","email","people","withEmail"],"additionalProperties":false},{"type":"null"}],"description":"How people are recognized. The token itself is never returned."},"connection":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Kind of Confluence the import reads through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["cloud","dataCenter"]},"site":{"type":"string","description":"Host name of the Confluence site, with the port when it is not 443."},"basePath":{"type":"string","description":"Context path of Confluence Data Center, such as `/confluence`, or empty."},"email":{"description":"Atlassian e-mail address the API token belongs to, or null.","type":["string","null"]},"account":{"description":"Name of the Confluence account the token belongs to.","type":["string","null"]},"selection":{"type":"array","items":{"type":"object","properties":{"importId":{"type":"string","format":"uuid","description":"ID of the import that reads the space."},"spaceKey":{"type":"string","description":"Key of the Confluence space."}},"required":["importId","spaceKey"],"additionalProperties":false},"description":"Spaces chosen with this connection whose imports are not started yet, one import per space, this import included. Empty once the import has started."}},"required":["kind","site","basePath","email","account","selection"],"additionalProperties":false},{"type":"null"}],"description":"The connection of an import through the Confluence API, or null. Several imports of the same importer can share one connection; the token is never returned."},"files":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","description":"Where the document comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload."},"complete":{"type":"boolean","description":"Whether the upload is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},"description":"The Word documents of a `word` import, in their order. Empty for other imports."},"options":{"type":"object","properties":{"spaceKey":{"description":"Key of the Confluence space read through the API or from a site backup.","type":"string"},"pageIds":{"description":"IDs of the top-level pages whose trees are imported; all pages when left out.","type":"array","items":{"type":"string"}},"blogPosts":{"description":"Whether blog posts are imported; true when left out.","type":"boolean"},"split":{"type":"string","description":"`file` makes each Word document one page, `heading` adds a subpage per top-level heading. New values can be added in later versions; handle unknown values.","x-extensible-enum":["file","heading"]},"knowledgeBase":{"description":"For a `markdown` import: whether the new space is a knowledge base.","type":"boolean"}},"additionalProperties":false,"description":"Options of the source."},"throttledUntil":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Until when Confluence asked Lunedo to slow down, or null. The import continues by itself. ISO 8601 timestamp in UTC."},"waitingFor":{"description":"Key of the Confluence space whose import over the same connection reads or runs first, or null. Imports sharing a connection run one after another; this one continues by itself.","type":["string","null"]},"tokenDeletedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the API token was deleted: when the import was accepted, discarded, stopped or failed, when the importer lost the permission to import, or when the draft was left alone for a week. ISO 8601 timestamp in UTC."},"sourceUrl":{"description":"Address of the Confluence site. Links to pages outside the export point there.","type":["string","null"]},"reviewers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"People who can read the quarantine space and the report."},"phase":{"anyOf":[{"type":"string","x-extensible-enum":["read","compare","space","people","pages","attachments","templates","content","comments","reactions","permissions","baseline","finish","lineage","moves","labels","deletions","done"]},{"type":"null"}],"description":"Step the import is in: `read` reads the export, then `space`, `people`, `pages`, `attachments`, `templates`, `content`, `comments`, `reactions`, `permissions`, `baseline` and `finish`; `done` after the last step. A re-import compares in `compare` and applies in `lineage`, `people`, `pages`, `moves`, `attachments`, `templates`, `content`, `labels`, `comments`, `reactions`, `deletions`, `baseline` and `finish`. New values can be added in later versions; handle unknown values."},"progress":{"type":"object","properties":{"done":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units done in the current step."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units of the current step, or 0 when not known."}},"required":["done","total"],"additionalProperties":false,"description":"Progress of the current step."},"found":{"anyOf":[{"type":"object","properties":{"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages in the export."},"blogPosts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Blog posts in the export."},"versions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Earlier versions of pages and blog posts."},"comments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Comments, including inline comments and replies."},"likes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Likes on pages, blog posts and comments."},"watchers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Watchers of pages and the space. They are counted, not imported."},"attachments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Attachments of these pages."},"attachmentBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the current attachment versions in bytes."},"people":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"People named in the export."},"macroKinds":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Different macros used on the pages."},"spaceKey":{"type":"string","description":"Key of the space in Confluence."},"spaceName":{"type":"string","description":"Name of the space in Confluence."}},"required":["pages","blogPosts","versions","comments","likes","watchers","attachments","attachmentBytes","people","macroKinds","spaceKey","spaceName"],"additionalProperties":false},{"type":"null"}],"description":"What the export contains, once it was read."},"sourceSpaces":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the space in Confluence."},"name":{"type":"string","description":"Name of the space in Confluence."}},"required":["key","name"],"additionalProperties":false}},{"type":"null"}],"description":"The spaces of a site backup, once it was read; choose one with `options.spaceKey`. Null for exports and backups of one space."},"counts":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"What was imported, by kind: `pages`, `blogPosts`, `versions`, `attachments`, `attachmentVersions`, `comments`, `inlineAnchored`, `inlineMoved`, `likes`, `watchers`, `people`, `peopleMatched`, `restrictions`, `groupsMissing` and `problems`."},"errorCode":{"description":"Why the export could not be read or the import failed, such as `notAnArchive`, `wrongFormat`, `archiveTooLarge`, `unsafeEntryName`, `xmlDeclaration`, `spaceChoiceRequired` (a site backup with several spaces; see `sourceSpaces`) or `internalError`.","type":["string","null"]},"quarantineSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."}},"required":["id","key"],"additionalProperties":false},{"type":"null"}],"description":"The space the import writes into."},"targetSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"name":{"type":"string","description":"Name of the space."}},"required":["id","key","name"],"additionalProperties":false},{"type":"null"}],"description":"For a re-import, the space created by the earlier import that the changes go into; otherwise null."},"reimportSpaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space a newer export of the same Confluence space can be imported into again, or null when this import offers no re-import."},"canManage":{"type":"boolean","description":"Whether the caller can change, start, stop, accept or discard the import."},"canResolve":{"type":"boolean","description":"Whether the caller can map people and groups of the import or apply a user list."},"canTakeOver":{"type":"boolean","description":"Whether the caller can take over a held import."},"startedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import finished or failed. ISO 8601 timestamp in UTC."},"decidedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import was accepted, discarded or stopped. ISO 8601 timestamp in UTC."},"fileExpiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When an uploaded file is deleted. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the import was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the import last changed. ISO 8601 timestamp in UTC."}},"required":["id","organizationId","importer","source","state","draftStep","file","spaceName","spaceKey","archived","history","peopleSource","connection","files","options","throttledUntil","waitingFor","tokenDeletedAt","sourceUrl","reviewers","phase","progress","found","sourceSpaces","counts","errorCode","quarantineSpace","targetSpace","reimportSpaceId","canManage","canResolve","canTakeOver","startedAt","finishedAt","decidedAt","fileExpiresAt","createdAt","updatedAt"],"additionalProperties":false,"description":"An import of a Confluence space."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0001","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0002","importer":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0003","name":"Alex Admin"},"source":"confluence-xml","state":"review","draftStep":3,"file":{"kind":"upload","name":"export.zip","size":1048576,"uploadId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0004","complete":true},"spaceName":"IT Operations","spaceKey":"ITOPS","archived":false,"sourceUrl":"https://example.atlassian.net/wiki","reviewers":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0005","name":"Robin Reviewer"}],"phase":null,"progress":{"done":0,"total":0},"found":{"pages":120,"blogPosts":6,"versions":340,"comments":85,"likes":30,"watchers":44,"attachments":40,"attachmentBytes":2048000,"people":12,"macroKinds":6,"spaceKey":"ITOPS","spaceName":"IT Operations"},"sourceSpaces":null,"history":false,"peopleSource":{"kind":"token","site":"example.atlassian.net","email":"alex@example.com","people":12,"withEmail":10},"connection":null,"files":[],"options":{},"throttledUntil":null,"waitingFor":null,"tokenDeletedAt":null,"counts":{"pages":120,"blogPosts":6,"attachments":40,"attachmentVersions":52,"comments":85,"people":12,"problems":7},"errorCode":null,"quarantineSpace":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0006","key":"ITOPS"},"targetSpace":null,"reimportSpaceId":null,"canManage":true,"canResolve":true,"canTakeOver":false,"startedAt":"2026-10-10T08:00:00.000Z","finishedAt":"2026-10-10T08:05:00.000Z","decidedAt":null,"fileExpiresAt":null,"createdAt":"2026-10-10T07:50:00.000Z","updatedAt":"2026-10-10T08:05:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidSelection`: The selection is not valid. `reimportSpaceFixed`: The space of a re-import cannot change. `wrongInput`: This kind of import does not take this input.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidSelection":{"value":{"type":"urn:lunedo:problem:invalidSelection","title":"The selection is not valid","status":400,"code":"invalidSelection"}},"reimportSpaceFixed":{"value":{"type":"urn:lunedo:problem:reimportSpaceFixed","title":"The space of a re-import cannot change","status":400,"code":"reimportSpaceFixed"}},"wrongInput":{"value":{"type":"urn:lunedo:problem:wrongInput","title":"This kind of import does not take this input","status":400,"code":"wrongInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`connectionMissing`: The import is not connected to Confluence. `importStarted`: The import has started.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"connectionMissing":{"value":{"type":"urn:lunedo:problem:connectionMissing","title":"The import is not connected to Confluence","status":409,"code":"connectionMissing"}},"importStarted":{"value":{"type":"urn:lunedo:problem:importStarted","title":"The import has started","status":409,"code":"importStarted"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/imports/{importId}/connection/spaces":{"get":{"operationId":"imports.connectionSpaces","summary":"List the Confluence spaces of a connection","description":"Lists the spaces the token of an import draft can read, by name. Spaces and pages the token cannot read are not listed by Confluence.\n\nRequires the permission `import.manage` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.manage","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The spaces.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"ID of the space in Confluence."},"key":{"type":"string","description":"Key of the space."},"name":{"type":"string","description":"Name of the space."},"personal":{"type":"boolean","description":"Whether it is a personal space."}},"required":["id","key","name","personal"],"additionalProperties":false},"description":"Spaces the token can read, by name."},"example":[{"id":"98306","key":"ITOPS","name":"IT Operations","personal":false}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `confluenceUnauthorized`: Confluence refused the token. `invalidInput`: The request is not valid. `wrongInput`: This kind of import does not take this input.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"confluenceUnauthorized":{"value":{"type":"urn:lunedo:problem:confluenceUnauthorized","title":"Confluence refused the token","status":400,"code":"confluenceUnauthorized"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"wrongInput":{"value":{"type":"urn:lunedo:problem:wrongInput","title":"This kind of import does not take this input","status":400,"code":"wrongInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`connectionMissing`: The import is not connected to Confluence. `importStarted`: The import has started.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"connectionMissing":{"value":{"type":"urn:lunedo:problem:connectionMissing","title":"The import is not connected to Confluence","status":409,"code":"connectionMissing"}},"importStarted":{"value":{"type":"urn:lunedo:problem:importStarted","title":"The import has started","status":409,"code":"importStarted"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"502":{"description":"`confluenceUnreachable`: Confluence could not be reached.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"confluenceUnreachable":{"value":{"type":"urn:lunedo:problem:confluenceUnreachable","title":"Confluence could not be reached","status":502,"code":"confluenceUnreachable"}}}}}}}}},"/api/v1/imports/{importId}/connection/spaces/{spaceKey}":{"get":{"operationId":"imports.connectionTree","summary":"Show what a Confluence space contains","description":"Counts the pages, blog posts and attachments of a space the token can read, with the top-level page trees to choose from.\n\nRequires the permission `import.manage` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.manage","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}},{"name":"spaceKey","in":"path","required":true,"description":"Key of the Confluence space.","schema":{"type":"string","minLength":1,"maxLength":255}}],"responses":{"200":{"description":"The space.","content":{"application/json":{"schema":{"type":"object","properties":{"spaceKey":{"type":"string","description":"Key of the space."},"spaceName":{"type":"string","description":"Name of the space."},"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages the token can read."},"blogPosts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Blog posts the token can read."},"attachmentBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the current attachment versions in bytes."},"complete":{"type":"boolean","description":"False when the space is so large that only part of it was counted; the numbers are then lower bounds."},"trees":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"ID of the top-level page."},"title":{"type":"string","description":"Title of the page."},"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages in this tree, the page itself included."},"attachmentBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the attachments in this tree in bytes."}},"required":["id","title","pages","attachmentBytes"],"additionalProperties":false},"description":"Top-level pages below the home page with their trees, by title."}},"required":["spaceKey","spaceName","pages","blogPosts","attachmentBytes","complete","trees"],"additionalProperties":false,"description":"What a space contains, for choosing what to import."},"example":{"spaceKey":"ITOPS","spaceName":"IT Operations","pages":128,"blogPosts":6,"attachmentBytes":104857600,"complete":true,"trees":[{"id":"98310","title":"Network","pages":86,"attachmentBytes":52428800}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `confluenceUnauthorized`: Confluence refused the token. `invalidInput`: The request is not valid. `wrongInput`: This kind of import does not take this input.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"confluenceUnauthorized":{"value":{"type":"urn:lunedo:problem:confluenceUnauthorized","title":"Confluence refused the token","status":400,"code":"confluenceUnauthorized"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"wrongInput":{"value":{"type":"urn:lunedo:problem:wrongInput","title":"This kind of import does not take this input","status":400,"code":"wrongInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`confluenceSpaceMissing`: The Confluence space does not exist or cannot be read. `notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"confluenceSpaceMissing":{"value":{"type":"urn:lunedo:problem:confluenceSpaceMissing","title":"The Confluence space does not exist or cannot be read","status":404,"code":"confluenceSpaceMissing"}},"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`connectionMissing`: The import is not connected to Confluence. `importStarted`: The import has started.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"connectionMissing":{"value":{"type":"urn:lunedo:problem:connectionMissing","title":"The import is not connected to Confluence","status":409,"code":"connectionMissing"}},"importStarted":{"value":{"type":"urn:lunedo:problem:importStarted","title":"The import has started","status":409,"code":"importStarted"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"502":{"description":"`confluenceUnreachable`: Confluence could not be reached.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"confluenceUnreachable":{"value":{"type":"urn:lunedo:problem:confluenceUnreachable","title":"Confluence could not be reached","status":502,"code":"confluenceUnreachable"}}}}}}}}},"/api/v1/imports/{importId}/discard":{"post":{"operationId":"imports.discard","summary":"Discard an import","description":"Deletes the quarantine space with everything in it and the report. Confirm with the key of the space. This cannot be undone.\n\nRequires the permission `import.manage` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.manage","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"confirmation":{"type":"string","maxLength":20,"description":"The key of the space, typed by the person to confirm."}},"required":["confirmation"],"additionalProperties":false,"description":"Confirmation of an action that cannot be undone."},"example":{"confirmation":"ITOPS"}}}},"responses":{"200":{"description":"The import.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the import."},"organizationId":{"type":"string","format":"uuid","description":"Organization the import belongs to."},"importer":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"The administrator who imports."},"source":{"type":"string","description":"What is imported: `confluence-xml` for the XML space export of Confluence Cloud or Data Center, `confluence-csv` for the CSV space export of Confluence Cloud, `confluence-cloud` and `confluence-dc` to read a space through the Confluence API, `markdown` for a ZIP file of Markdown files, `word` for Word documents (`.docx`). New values can be added in later versions; handle unknown values.","x-extensible-enum":["confluence-xml","confluence-csv","confluence-cloud","confluence-dc","markdown","word"]},"state":{"type":"string","description":"State of the import. `draft` while the wizard is filled in, `analyzing` while the export is read, `ready` when it can be started, `running` while it imports, `held` when the importing administrator lost the permission and another administrator has to take over, `stopping` and `discarding` while the quarantine space is deleted, `review` when the quarantine space waits for a decision, `accepted`, `discarded`, `stopped` and `failed` at the end. A re-import is in `running` while it compares or applies, in `review` while changes wait for a decision, `accepted` when everything is applied, and `superseded` when a newer re-import of the same space replaced it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["draft","analyzing","ready","running","held","stopping","review","accepting","accepted","discarding","discarded","stopped","failed","superseded"]},"draftStep":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Step of the wizard the importer was on, for continuing a draft."},"file":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Where the export comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload","folder"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes, or null when not known yet."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload, or null for a file in the import folder."},"complete":{"type":"boolean","description":"Whether the file is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},{"type":"null"}],"description":"The export file, or null when none is chosen yet."},"spaceName":{"description":"Name of the new space.","type":["string","null"]},"spaceKey":{"description":"Key of the new space.","type":["string","null"]},"archived":{"type":"boolean","description":"Whether the space becomes archived when the import is accepted."},"history":{"type":"boolean","description":"Whether every Confluence version becomes a Lunedo version, or only the current state is imported."},"peopleSource":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"How people are recognized: `token` reads names and e-mail addresses with a read-only Atlassian API token, `list` uses a user list exported from the Atlassian administration, `skip` keeps every author as a placeholder, `source` takes the names Confluence Data Center returns through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["token","list","skip","source"]},"site":{"description":"Confluence site the token is used with, or null.","type":["string","null"]},"email":{"description":"Atlassian e-mail address the token belongs to, or null.","type":["string","null"]},"people":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"People of the export the token could read, or people in the user list; null when unknown."},"withEmail":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Of these, people with a visible e-mail address."}},"required":["kind","site","email","people","withEmail"],"additionalProperties":false},{"type":"null"}],"description":"How people are recognized. The token itself is never returned."},"connection":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Kind of Confluence the import reads through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["cloud","dataCenter"]},"site":{"type":"string","description":"Host name of the Confluence site, with the port when it is not 443."},"basePath":{"type":"string","description":"Context path of Confluence Data Center, such as `/confluence`, or empty."},"email":{"description":"Atlassian e-mail address the API token belongs to, or null.","type":["string","null"]},"account":{"description":"Name of the Confluence account the token belongs to.","type":["string","null"]},"selection":{"type":"array","items":{"type":"object","properties":{"importId":{"type":"string","format":"uuid","description":"ID of the import that reads the space."},"spaceKey":{"type":"string","description":"Key of the Confluence space."}},"required":["importId","spaceKey"],"additionalProperties":false},"description":"Spaces chosen with this connection whose imports are not started yet, one import per space, this import included. Empty once the import has started."}},"required":["kind","site","basePath","email","account","selection"],"additionalProperties":false},{"type":"null"}],"description":"The connection of an import through the Confluence API, or null. Several imports of the same importer can share one connection; the token is never returned."},"files":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","description":"Where the document comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload."},"complete":{"type":"boolean","description":"Whether the upload is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},"description":"The Word documents of a `word` import, in their order. Empty for other imports."},"options":{"type":"object","properties":{"spaceKey":{"description":"Key of the Confluence space read through the API or from a site backup.","type":"string"},"pageIds":{"description":"IDs of the top-level pages whose trees are imported; all pages when left out.","type":"array","items":{"type":"string"}},"blogPosts":{"description":"Whether blog posts are imported; true when left out.","type":"boolean"},"split":{"type":"string","description":"`file` makes each Word document one page, `heading` adds a subpage per top-level heading. New values can be added in later versions; handle unknown values.","x-extensible-enum":["file","heading"]},"knowledgeBase":{"description":"For a `markdown` import: whether the new space is a knowledge base.","type":"boolean"}},"additionalProperties":false,"description":"Options of the source."},"throttledUntil":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Until when Confluence asked Lunedo to slow down, or null. The import continues by itself. ISO 8601 timestamp in UTC."},"waitingFor":{"description":"Key of the Confluence space whose import over the same connection reads or runs first, or null. Imports sharing a connection run one after another; this one continues by itself.","type":["string","null"]},"tokenDeletedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the API token was deleted: when the import was accepted, discarded, stopped or failed, when the importer lost the permission to import, or when the draft was left alone for a week. ISO 8601 timestamp in UTC."},"sourceUrl":{"description":"Address of the Confluence site. Links to pages outside the export point there.","type":["string","null"]},"reviewers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"People who can read the quarantine space and the report."},"phase":{"anyOf":[{"type":"string","x-extensible-enum":["read","compare","space","people","pages","attachments","templates","content","comments","reactions","permissions","baseline","finish","lineage","moves","labels","deletions","done"]},{"type":"null"}],"description":"Step the import is in: `read` reads the export, then `space`, `people`, `pages`, `attachments`, `templates`, `content`, `comments`, `reactions`, `permissions`, `baseline` and `finish`; `done` after the last step. A re-import compares in `compare` and applies in `lineage`, `people`, `pages`, `moves`, `attachments`, `templates`, `content`, `labels`, `comments`, `reactions`, `deletions`, `baseline` and `finish`. New values can be added in later versions; handle unknown values."},"progress":{"type":"object","properties":{"done":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units done in the current step."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units of the current step, or 0 when not known."}},"required":["done","total"],"additionalProperties":false,"description":"Progress of the current step."},"found":{"anyOf":[{"type":"object","properties":{"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages in the export."},"blogPosts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Blog posts in the export."},"versions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Earlier versions of pages and blog posts."},"comments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Comments, including inline comments and replies."},"likes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Likes on pages, blog posts and comments."},"watchers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Watchers of pages and the space. They are counted, not imported."},"attachments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Attachments of these pages."},"attachmentBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the current attachment versions in bytes."},"people":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"People named in the export."},"macroKinds":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Different macros used on the pages."},"spaceKey":{"type":"string","description":"Key of the space in Confluence."},"spaceName":{"type":"string","description":"Name of the space in Confluence."}},"required":["pages","blogPosts","versions","comments","likes","watchers","attachments","attachmentBytes","people","macroKinds","spaceKey","spaceName"],"additionalProperties":false},{"type":"null"}],"description":"What the export contains, once it was read."},"sourceSpaces":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the space in Confluence."},"name":{"type":"string","description":"Name of the space in Confluence."}},"required":["key","name"],"additionalProperties":false}},{"type":"null"}],"description":"The spaces of a site backup, once it was read; choose one with `options.spaceKey`. Null for exports and backups of one space."},"counts":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"What was imported, by kind: `pages`, `blogPosts`, `versions`, `attachments`, `attachmentVersions`, `comments`, `inlineAnchored`, `inlineMoved`, `likes`, `watchers`, `people`, `peopleMatched`, `restrictions`, `groupsMissing` and `problems`."},"errorCode":{"description":"Why the export could not be read or the import failed, such as `notAnArchive`, `wrongFormat`, `archiveTooLarge`, `unsafeEntryName`, `xmlDeclaration`, `spaceChoiceRequired` (a site backup with several spaces; see `sourceSpaces`) or `internalError`.","type":["string","null"]},"quarantineSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."}},"required":["id","key"],"additionalProperties":false},{"type":"null"}],"description":"The space the import writes into."},"targetSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"name":{"type":"string","description":"Name of the space."}},"required":["id","key","name"],"additionalProperties":false},{"type":"null"}],"description":"For a re-import, the space created by the earlier import that the changes go into; otherwise null."},"reimportSpaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space a newer export of the same Confluence space can be imported into again, or null when this import offers no re-import."},"canManage":{"type":"boolean","description":"Whether the caller can change, start, stop, accept or discard the import."},"canResolve":{"type":"boolean","description":"Whether the caller can map people and groups of the import or apply a user list."},"canTakeOver":{"type":"boolean","description":"Whether the caller can take over a held import."},"startedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import finished or failed. ISO 8601 timestamp in UTC."},"decidedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import was accepted, discarded or stopped. ISO 8601 timestamp in UTC."},"fileExpiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When an uploaded file is deleted. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the import was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the import last changed. ISO 8601 timestamp in UTC."}},"required":["id","organizationId","importer","source","state","draftStep","file","spaceName","spaceKey","archived","history","peopleSource","connection","files","options","throttledUntil","waitingFor","tokenDeletedAt","sourceUrl","reviewers","phase","progress","found","sourceSpaces","counts","errorCode","quarantineSpace","targetSpace","reimportSpaceId","canManage","canResolve","canTakeOver","startedAt","finishedAt","decidedAt","fileExpiresAt","createdAt","updatedAt"],"additionalProperties":false,"description":"An import of a Confluence space."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0001","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0002","importer":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0003","name":"Alex Admin"},"source":"confluence-xml","state":"discarding","draftStep":3,"file":{"kind":"upload","name":"export.zip","size":1048576,"uploadId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0004","complete":true},"spaceName":"IT Operations","spaceKey":"ITOPS","archived":false,"sourceUrl":"https://example.atlassian.net/wiki","reviewers":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0005","name":"Robin Reviewer"}],"phase":null,"progress":{"done":0,"total":0},"found":{"pages":120,"blogPosts":6,"versions":340,"comments":85,"likes":30,"watchers":44,"attachments":40,"attachmentBytes":2048000,"people":12,"macroKinds":6,"spaceKey":"ITOPS","spaceName":"IT Operations"},"sourceSpaces":null,"history":false,"peopleSource":{"kind":"token","site":"example.atlassian.net","email":"alex@example.com","people":12,"withEmail":10},"connection":null,"files":[],"options":{},"throttledUntil":null,"waitingFor":null,"tokenDeletedAt":null,"counts":{"pages":120,"blogPosts":6,"attachments":40,"attachmentVersions":52,"comments":85,"people":12,"problems":7},"errorCode":null,"quarantineSpace":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0006","key":"ITOPS"},"targetSpace":null,"reimportSpaceId":null,"canManage":true,"canResolve":true,"canTakeOver":false,"startedAt":"2026-10-10T08:00:00.000Z","finishedAt":"2026-10-10T08:05:00.000Z","decidedAt":null,"fileExpiresAt":null,"createdAt":"2026-10-10T07:50:00.000Z","updatedAt":"2026-10-10T08:05:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `confirmationMismatch`: The confirmation does not match. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"confirmationMismatch":{"value":{"type":"urn:lunedo:problem:confirmationMismatch","title":"The confirmation does not match","status":400,"code":"confirmationMismatch"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`importNotInReview`: The import is not waiting for a decision.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"importNotInReview":{"value":{"type":"urn:lunedo:problem:importNotInReview","title":"The import is not waiting for a decision","status":409,"code":"importNotInReview"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/imports/{importId}/groups":{"get":{"operationId":"imports.groups","summary":"List the groups of an import","description":"Lists the Confluence groups named in space permissions and page restrictions, and the group of the organization each is mapped to. Groups are matched by name, including synchronized groups; nothing is created automatically.\n\nRequires the permission `import.view` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.view","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The groups.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Lower-case name of the group in Confluence, used in the address."},"name":{"type":"string","description":"Name of the group in Confluence."},"group":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the group."},"name":{"type":"string","description":"Name of the group."}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"The group of the organization it is mapped to, or null."},"spaceRole":{"anyOf":[{"type":"string","description":"Role in the space: `reader`, `commenter`, `editor` or `admin` (space admin). New values can be added in later versions; handle unknown values.","x-extensible-enum":["reader","commenter","editor","admin"]},{"type":"null"}],"description":"Role the group had in the Confluence space, or null."},"restrictedPages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Restricted pages the group may open."}},"required":["key","name","group","spaceRole","restrictedPages"],"additionalProperties":false,"description":"A group named in the export."},"description":"Groups named in the export, unmapped first."},"example":[{"key":"contractors","name":"contractors","group":null,"spaceRole":"reader","restrictedPages":2}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`reportUnavailable`: The report is not available yet.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"reportUnavailable":{"value":{"type":"urn:lunedo:problem:reportUnavailable","title":"The report is not available yet","status":409,"code":"reportUnavailable"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/imports/{importId}/groups/{groupKey}":{"put":{"operationId":"imports.mapGroup","summary":"Map a group of an import","description":"Maps a Confluence group to an existing group of the organization, or creates a local group with its name (this needs the permission to create groups). The group takes its place on page restrictions at once; restrictions only narrow access, so its members still need a role in the space. Its space role applies when the import is accepted. Nobody is notified. When the caller belongs to or manages the chosen group, or creates it, the audit log records this as a self-addition with the import named.\n\nRequires the permission `import.resolve` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.resolve","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}},{"name":"groupKey","in":"path","required":true,"description":"Lower-case name of the group in Confluence.","schema":{"type":"string","minLength":1,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"groupId":{"type":"string","format":"uuid","description":"ID of an existing group of the organization."}},"required":["groupId"],"additionalProperties":false},{"type":"object","properties":{"create":{"type":"boolean","const":true,"description":"Create a local group with the name from Confluence."}},"required":["create"],"additionalProperties":false}],"description":"The group a Confluence group becomes."},"example":{"create":true}}}},"responses":{"200":{"description":"The group.","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Lower-case name of the group in Confluence, used in the address."},"name":{"type":"string","description":"Name of the group in Confluence."},"group":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the group."},"name":{"type":"string","description":"Name of the group."}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"The group of the organization it is mapped to, or null."},"spaceRole":{"anyOf":[{"type":"string","description":"Role in the space: `reader`, `commenter`, `editor` or `admin` (space admin). New values can be added in later versions; handle unknown values.","x-extensible-enum":["reader","commenter","editor","admin"]},{"type":"null"}],"description":"Role the group had in the Confluence space, or null."},"restrictedPages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Restricted pages the group may open."}},"required":["key","name","group","spaceRole","restrictedPages"],"additionalProperties":false,"description":"A group named in the export."},"example":{"key":"contractors","name":"contractors","group":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0001","name":"contractors"},"spaceRole":"reader","restrictedPages":2}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`groupNotFound`: The group does not exist. `notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"groupNotFound":{"value":{"type":"urn:lunedo:problem:groupNotFound","title":"The group does not exist","status":404,"code":"groupNotFound"}},"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`groupAlreadyMapped`: The group is mapped already. `groupNameTaken`: The group name is taken. `importNotResolvable`: People and groups can be mapped once the import has finished.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"groupAlreadyMapped":{"value":{"type":"urn:lunedo:problem:groupAlreadyMapped","title":"The group is mapped already","status":409,"code":"groupAlreadyMapped"}},"groupNameTaken":{"value":{"type":"urn:lunedo:problem:groupNameTaken","title":"The group name is taken","status":409,"code":"groupNameTaken"}},"importNotResolvable":{"value":{"type":"urn:lunedo:problem:importNotResolvable","title":"People and groups can be mapped once the import has finished","status":409,"code":"importNotResolvable"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/imports/{importId}/people":{"get":{"operationId":"imports.people","summary":"List the placeholders of an import","description":"Lists the people of the export who became placeholders, with the content they own, the account they were mapped to and members with a similar name. Similar names are only offered; nobody is mapped by name automatically.\n\nRequires the permission `import.view` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.view","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}},{"name":"q","in":"query","required":false,"description":"Part of the name, e-mail address or Atlassian ID.","schema":{"type":"string","maxLength":200}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"A page of placeholders.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the placeholder account."},"name":{"type":"string","description":"Best name known, or the Atlassian ID when no name is known."},"externalId":{"type":"string","description":"Atlassian account ID or Confluence user key."},"email":{"description":"E-mail address known from the user source, or null.","type":["string","null"]},"named":{"type":"boolean","description":"Whether a name is known."},"items":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages and blog posts the person created in this import."},"comments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Comments the person wrote in this import."},"restrictedPages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Restricted pages the person may open."},"spaceRole":{"anyOf":[{"type":"string","description":"Role in the space: `reader`, `commenter`, `editor` or `admin` (space admin). New values can be added in later versions; handle unknown values.","x-extensible-enum":["reader","commenter","editor","admin"]},{"type":"null"}],"description":"Role the person had in the Confluence space, or null."},"mappedTo":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"The account the placeholder was mapped to, or null."},"candidates":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"Members with a similar name, offered for confirmation. Never mapped automatically."}},"required":["id","name","externalId","email","named","items","comments","restrictedPages","spaceRole","mappedTo","candidates"],"additionalProperties":false,"description":"A person of the export without an account."},"description":"Placeholders, those still open first."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of all placeholders of the import."},"mapped":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of placeholders mapped to accounts."},"nextCursor":{"description":"Cursor of the next page, or null on the last page.","type":["string","null"]}},"required":["items","total","mapped","nextCursor"],"additionalProperties":false,"description":"People of an import that became placeholders."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0001","name":"J. Weber","externalId":"557058:4f1c0000-0000-0000-0000-000000000000","email":null,"named":true,"items":14,"comments":31,"restrictedPages":0,"spaceRole":"editor","mappedTo":null,"candidates":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0003","name":"Jana Weber"}]}],"total":13,"mapped":0,"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`reportUnavailable`: The report is not available yet.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"reportUnavailable":{"value":{"type":"urn:lunedo:problem:reportUnavailable","title":"The report is not available yet","status":409,"code":"reportUnavailable"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/imports/{importId}/people-source":{"put":{"operationId":"imports.peopleSource","summary":"Choose how people are recognized","description":"Sets the user source of an import draft. With `token`, Lunedo checks the read-only Atlassian API token against the given site at once, stores it encrypted, uses it only while the import runs and deletes it when the import is accepted, discarded, stopped or fails. Only `https` sites under `atlassian.net` or hosts the instance administrator allowed are contacted. With `skip`, every author becomes a placeholder. A user list is sent to `people-source/user-list`.\n\nRequires the permission `import.manage` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.manage","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"token","description":"Read names and e-mail addresses with a read-only Atlassian API token."},"site":{"type":"string","maxLength":300,"description":"Confluence Cloud site, such as `example.atlassian.net`. Other hosts work only when the instance administrator allowed them."},"email":{"type":"string","maxLength":320,"description":"E-mail address of the Atlassian account the token belongs to."},"token":{"type":"string","maxLength":1000,"description":"The API token. It is checked at once, stored encrypted and deleted when the import ends."}},"required":["kind","site","email","token"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"skip","description":"Keep every author as a placeholder named by an Atlassian ID."},"confirmed":{"type":"boolean","description":"Must be true: the administrator confirms that authors become placeholders."}},"required":["kind","confirmed"],"additionalProperties":false}],"description":"How the import recognizes people. A user list is sent to its own endpoint."},"example":{"kind":"token","site":"example.atlassian.net","email":"alex@example.com","token":"ATATT3x…"}}}},"responses":{"200":{"description":"The import.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the import."},"organizationId":{"type":"string","format":"uuid","description":"Organization the import belongs to."},"importer":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"The administrator who imports."},"source":{"type":"string","description":"What is imported: `confluence-xml` for the XML space export of Confluence Cloud or Data Center, `confluence-csv` for the CSV space export of Confluence Cloud, `confluence-cloud` and `confluence-dc` to read a space through the Confluence API, `markdown` for a ZIP file of Markdown files, `word` for Word documents (`.docx`). New values can be added in later versions; handle unknown values.","x-extensible-enum":["confluence-xml","confluence-csv","confluence-cloud","confluence-dc","markdown","word"]},"state":{"type":"string","description":"State of the import. `draft` while the wizard is filled in, `analyzing` while the export is read, `ready` when it can be started, `running` while it imports, `held` when the importing administrator lost the permission and another administrator has to take over, `stopping` and `discarding` while the quarantine space is deleted, `review` when the quarantine space waits for a decision, `accepted`, `discarded`, `stopped` and `failed` at the end. A re-import is in `running` while it compares or applies, in `review` while changes wait for a decision, `accepted` when everything is applied, and `superseded` when a newer re-import of the same space replaced it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["draft","analyzing","ready","running","held","stopping","review","accepting","accepted","discarding","discarded","stopped","failed","superseded"]},"draftStep":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Step of the wizard the importer was on, for continuing a draft."},"file":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Where the export comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload","folder"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes, or null when not known yet."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload, or null for a file in the import folder."},"complete":{"type":"boolean","description":"Whether the file is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},{"type":"null"}],"description":"The export file, or null when none is chosen yet."},"spaceName":{"description":"Name of the new space.","type":["string","null"]},"spaceKey":{"description":"Key of the new space.","type":["string","null"]},"archived":{"type":"boolean","description":"Whether the space becomes archived when the import is accepted."},"history":{"type":"boolean","description":"Whether every Confluence version becomes a Lunedo version, or only the current state is imported."},"peopleSource":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"How people are recognized: `token` reads names and e-mail addresses with a read-only Atlassian API token, `list` uses a user list exported from the Atlassian administration, `skip` keeps every author as a placeholder, `source` takes the names Confluence Data Center returns through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["token","list","skip","source"]},"site":{"description":"Confluence site the token is used with, or null.","type":["string","null"]},"email":{"description":"Atlassian e-mail address the token belongs to, or null.","type":["string","null"]},"people":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"People of the export the token could read, or people in the user list; null when unknown."},"withEmail":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Of these, people with a visible e-mail address."}},"required":["kind","site","email","people","withEmail"],"additionalProperties":false},{"type":"null"}],"description":"How people are recognized. The token itself is never returned."},"connection":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Kind of Confluence the import reads through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["cloud","dataCenter"]},"site":{"type":"string","description":"Host name of the Confluence site, with the port when it is not 443."},"basePath":{"type":"string","description":"Context path of Confluence Data Center, such as `/confluence`, or empty."},"email":{"description":"Atlassian e-mail address the API token belongs to, or null.","type":["string","null"]},"account":{"description":"Name of the Confluence account the token belongs to.","type":["string","null"]},"selection":{"type":"array","items":{"type":"object","properties":{"importId":{"type":"string","format":"uuid","description":"ID of the import that reads the space."},"spaceKey":{"type":"string","description":"Key of the Confluence space."}},"required":["importId","spaceKey"],"additionalProperties":false},"description":"Spaces chosen with this connection whose imports are not started yet, one import per space, this import included. Empty once the import has started."}},"required":["kind","site","basePath","email","account","selection"],"additionalProperties":false},{"type":"null"}],"description":"The connection of an import through the Confluence API, or null. Several imports of the same importer can share one connection; the token is never returned."},"files":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","description":"Where the document comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload."},"complete":{"type":"boolean","description":"Whether the upload is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},"description":"The Word documents of a `word` import, in their order. Empty for other imports."},"options":{"type":"object","properties":{"spaceKey":{"description":"Key of the Confluence space read through the API or from a site backup.","type":"string"},"pageIds":{"description":"IDs of the top-level pages whose trees are imported; all pages when left out.","type":"array","items":{"type":"string"}},"blogPosts":{"description":"Whether blog posts are imported; true when left out.","type":"boolean"},"split":{"type":"string","description":"`file` makes each Word document one page, `heading` adds a subpage per top-level heading. New values can be added in later versions; handle unknown values.","x-extensible-enum":["file","heading"]},"knowledgeBase":{"description":"For a `markdown` import: whether the new space is a knowledge base.","type":"boolean"}},"additionalProperties":false,"description":"Options of the source."},"throttledUntil":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Until when Confluence asked Lunedo to slow down, or null. The import continues by itself. ISO 8601 timestamp in UTC."},"waitingFor":{"description":"Key of the Confluence space whose import over the same connection reads or runs first, or null. Imports sharing a connection run one after another; this one continues by itself.","type":["string","null"]},"tokenDeletedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the API token was deleted: when the import was accepted, discarded, stopped or failed, when the importer lost the permission to import, or when the draft was left alone for a week. ISO 8601 timestamp in UTC."},"sourceUrl":{"description":"Address of the Confluence site. Links to pages outside the export point there.","type":["string","null"]},"reviewers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"People who can read the quarantine space and the report."},"phase":{"anyOf":[{"type":"string","x-extensible-enum":["read","compare","space","people","pages","attachments","templates","content","comments","reactions","permissions","baseline","finish","lineage","moves","labels","deletions","done"]},{"type":"null"}],"description":"Step the import is in: `read` reads the export, then `space`, `people`, `pages`, `attachments`, `templates`, `content`, `comments`, `reactions`, `permissions`, `baseline` and `finish`; `done` after the last step. A re-import compares in `compare` and applies in `lineage`, `people`, `pages`, `moves`, `attachments`, `templates`, `content`, `labels`, `comments`, `reactions`, `deletions`, `baseline` and `finish`. New values can be added in later versions; handle unknown values."},"progress":{"type":"object","properties":{"done":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units done in the current step."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units of the current step, or 0 when not known."}},"required":["done","total"],"additionalProperties":false,"description":"Progress of the current step."},"found":{"anyOf":[{"type":"object","properties":{"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages in the export."},"blogPosts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Blog posts in the export."},"versions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Earlier versions of pages and blog posts."},"comments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Comments, including inline comments and replies."},"likes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Likes on pages, blog posts and comments."},"watchers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Watchers of pages and the space. They are counted, not imported."},"attachments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Attachments of these pages."},"attachmentBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the current attachment versions in bytes."},"people":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"People named in the export."},"macroKinds":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Different macros used on the pages."},"spaceKey":{"type":"string","description":"Key of the space in Confluence."},"spaceName":{"type":"string","description":"Name of the space in Confluence."}},"required":["pages","blogPosts","versions","comments","likes","watchers","attachments","attachmentBytes","people","macroKinds","spaceKey","spaceName"],"additionalProperties":false},{"type":"null"}],"description":"What the export contains, once it was read."},"sourceSpaces":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the space in Confluence."},"name":{"type":"string","description":"Name of the space in Confluence."}},"required":["key","name"],"additionalProperties":false}},{"type":"null"}],"description":"The spaces of a site backup, once it was read; choose one with `options.spaceKey`. Null for exports and backups of one space."},"counts":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"What was imported, by kind: `pages`, `blogPosts`, `versions`, `attachments`, `attachmentVersions`, `comments`, `inlineAnchored`, `inlineMoved`, `likes`, `watchers`, `people`, `peopleMatched`, `restrictions`, `groupsMissing` and `problems`."},"errorCode":{"description":"Why the export could not be read or the import failed, such as `notAnArchive`, `wrongFormat`, `archiveTooLarge`, `unsafeEntryName`, `xmlDeclaration`, `spaceChoiceRequired` (a site backup with several spaces; see `sourceSpaces`) or `internalError`.","type":["string","null"]},"quarantineSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."}},"required":["id","key"],"additionalProperties":false},{"type":"null"}],"description":"The space the import writes into."},"targetSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"name":{"type":"string","description":"Name of the space."}},"required":["id","key","name"],"additionalProperties":false},{"type":"null"}],"description":"For a re-import, the space created by the earlier import that the changes go into; otherwise null."},"reimportSpaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space a newer export of the same Confluence space can be imported into again, or null when this import offers no re-import."},"canManage":{"type":"boolean","description":"Whether the caller can change, start, stop, accept or discard the import."},"canResolve":{"type":"boolean","description":"Whether the caller can map people and groups of the import or apply a user list."},"canTakeOver":{"type":"boolean","description":"Whether the caller can take over a held import."},"startedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import finished or failed. ISO 8601 timestamp in UTC."},"decidedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import was accepted, discarded or stopped. ISO 8601 timestamp in UTC."},"fileExpiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When an uploaded file is deleted. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the import was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the import last changed. ISO 8601 timestamp in UTC."}},"required":["id","organizationId","importer","source","state","draftStep","file","spaceName","spaceKey","archived","history","peopleSource","connection","files","options","throttledUntil","waitingFor","tokenDeletedAt","sourceUrl","reviewers","phase","progress","found","sourceSpaces","counts","errorCode","quarantineSpace","targetSpace","reimportSpaceId","canManage","canResolve","canTakeOver","startedAt","finishedAt","decidedAt","fileExpiresAt","createdAt","updatedAt"],"additionalProperties":false,"description":"An import of a Confluence space."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0001","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0002","importer":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0003","name":"Alex Admin"},"source":"confluence-xml","state":"review","draftStep":3,"file":{"kind":"upload","name":"export.zip","size":1048576,"uploadId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0004","complete":true},"spaceName":"IT Operations","spaceKey":"ITOPS","archived":false,"sourceUrl":"https://example.atlassian.net/wiki","reviewers":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0005","name":"Robin Reviewer"}],"phase":null,"progress":{"done":0,"total":0},"found":{"pages":120,"blogPosts":6,"versions":340,"comments":85,"likes":30,"watchers":44,"attachments":40,"attachmentBytes":2048000,"people":12,"macroKinds":6,"spaceKey":"ITOPS","spaceName":"IT Operations"},"sourceSpaces":null,"history":false,"peopleSource":{"kind":"token","site":"example.atlassian.net","email":"alex@example.com","people":12,"withEmail":10},"connection":null,"files":[],"options":{},"throttledUntil":null,"waitingFor":null,"tokenDeletedAt":null,"counts":{"pages":120,"blogPosts":6,"attachments":40,"attachmentVersions":52,"comments":85,"people":12,"problems":7},"errorCode":null,"quarantineSpace":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0006","key":"ITOPS"},"targetSpace":null,"reimportSpaceId":null,"canManage":true,"canResolve":true,"canTakeOver":false,"startedAt":"2026-10-10T08:00:00.000Z","finishedAt":"2026-10-10T08:05:00.000Z","decidedAt":null,"fileExpiresAt":null,"createdAt":"2026-10-10T07:50:00.000Z","updatedAt":"2026-10-10T08:05:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `atlassianUnauthorized`: Atlassian refused the API token. `invalidAtlassianEmail`: The Atlassian e-mail address is not valid. `invalidAtlassianSite`: The Atlassian site is not allowed. `invalidAtlassianToken`: The Atlassian API token is not valid. `invalidInput`: The request is not valid. `skipNotConfirmed`: Skipping the people step needs a confirmation.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"atlassianUnauthorized":{"value":{"type":"urn:lunedo:problem:atlassianUnauthorized","title":"Atlassian refused the API token","status":400,"code":"atlassianUnauthorized"}},"invalidAtlassianEmail":{"value":{"type":"urn:lunedo:problem:invalidAtlassianEmail","title":"The Atlassian e-mail address is not valid","status":400,"code":"invalidAtlassianEmail"}},"invalidAtlassianSite":{"value":{"type":"urn:lunedo:problem:invalidAtlassianSite","title":"The Atlassian site is not allowed","status":400,"code":"invalidAtlassianSite"}},"invalidAtlassianToken":{"value":{"type":"urn:lunedo:problem:invalidAtlassianToken","title":"The Atlassian API token is not valid","status":400,"code":"invalidAtlassianToken"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"skipNotConfirmed":{"value":{"type":"urn:lunedo:problem:skipNotConfirmed","title":"Skipping the people step needs a confirmation","status":400,"code":"skipNotConfirmed"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`importStarted`: The import has started.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"importStarted":{"value":{"type":"urn:lunedo:problem:importStarted","title":"The import has started","status":409,"code":"importStarted"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"502":{"description":"`atlassianUnreachable`: Atlassian could not be reached.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"atlassianUnreachable":{"value":{"type":"urn:lunedo:problem:atlassianUnreachable","title":"Atlassian could not be reached","status":502,"code":"atlassianUnreachable"}}}}}},"503":{"description":"`atlassianRateLimited`: Atlassian asked to slow down. `maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"atlassianRateLimited":{"value":{"type":"urn:lunedo:problem:atlassianRateLimited","title":"Atlassian asked to slow down","status":503,"code":"atlassianRateLimited"}},"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/imports/{importId}/people-source/user-list":{"put":{"operationId":"imports.peopleSourceList","summary":"Use a user list to recognize people","description":"Sets a user list exported from the Atlassian administration (admin.atlassian.com › Directory › Users › Export users) as the user source of an import draft. Send the CSV file with `Content-Type: text/csv`, up to 10 MB. People are matched by e-mail address only.\n\nRequires the permission `import.manage` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.manage","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"description":"The user list as CSV with a header row.","content":{"text/csv":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"The import.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the import."},"organizationId":{"type":"string","format":"uuid","description":"Organization the import belongs to."},"importer":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"The administrator who imports."},"source":{"type":"string","description":"What is imported: `confluence-xml` for the XML space export of Confluence Cloud or Data Center, `confluence-csv` for the CSV space export of Confluence Cloud, `confluence-cloud` and `confluence-dc` to read a space through the Confluence API, `markdown` for a ZIP file of Markdown files, `word` for Word documents (`.docx`). New values can be added in later versions; handle unknown values.","x-extensible-enum":["confluence-xml","confluence-csv","confluence-cloud","confluence-dc","markdown","word"]},"state":{"type":"string","description":"State of the import. `draft` while the wizard is filled in, `analyzing` while the export is read, `ready` when it can be started, `running` while it imports, `held` when the importing administrator lost the permission and another administrator has to take over, `stopping` and `discarding` while the quarantine space is deleted, `review` when the quarantine space waits for a decision, `accepted`, `discarded`, `stopped` and `failed` at the end. A re-import is in `running` while it compares or applies, in `review` while changes wait for a decision, `accepted` when everything is applied, and `superseded` when a newer re-import of the same space replaced it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["draft","analyzing","ready","running","held","stopping","review","accepting","accepted","discarding","discarded","stopped","failed","superseded"]},"draftStep":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Step of the wizard the importer was on, for continuing a draft."},"file":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Where the export comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload","folder"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes, or null when not known yet."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload, or null for a file in the import folder."},"complete":{"type":"boolean","description":"Whether the file is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},{"type":"null"}],"description":"The export file, or null when none is chosen yet."},"spaceName":{"description":"Name of the new space.","type":["string","null"]},"spaceKey":{"description":"Key of the new space.","type":["string","null"]},"archived":{"type":"boolean","description":"Whether the space becomes archived when the import is accepted."},"history":{"type":"boolean","description":"Whether every Confluence version becomes a Lunedo version, or only the current state is imported."},"peopleSource":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"How people are recognized: `token` reads names and e-mail addresses with a read-only Atlassian API token, `list` uses a user list exported from the Atlassian administration, `skip` keeps every author as a placeholder, `source` takes the names Confluence Data Center returns through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["token","list","skip","source"]},"site":{"description":"Confluence site the token is used with, or null.","type":["string","null"]},"email":{"description":"Atlassian e-mail address the token belongs to, or null.","type":["string","null"]},"people":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"People of the export the token could read, or people in the user list; null when unknown."},"withEmail":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Of these, people with a visible e-mail address."}},"required":["kind","site","email","people","withEmail"],"additionalProperties":false},{"type":"null"}],"description":"How people are recognized. The token itself is never returned."},"connection":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Kind of Confluence the import reads through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["cloud","dataCenter"]},"site":{"type":"string","description":"Host name of the Confluence site, with the port when it is not 443."},"basePath":{"type":"string","description":"Context path of Confluence Data Center, such as `/confluence`, or empty."},"email":{"description":"Atlassian e-mail address the API token belongs to, or null.","type":["string","null"]},"account":{"description":"Name of the Confluence account the token belongs to.","type":["string","null"]},"selection":{"type":"array","items":{"type":"object","properties":{"importId":{"type":"string","format":"uuid","description":"ID of the import that reads the space."},"spaceKey":{"type":"string","description":"Key of the Confluence space."}},"required":["importId","spaceKey"],"additionalProperties":false},"description":"Spaces chosen with this connection whose imports are not started yet, one import per space, this import included. Empty once the import has started."}},"required":["kind","site","basePath","email","account","selection"],"additionalProperties":false},{"type":"null"}],"description":"The connection of an import through the Confluence API, or null. Several imports of the same importer can share one connection; the token is never returned."},"files":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","description":"Where the document comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload."},"complete":{"type":"boolean","description":"Whether the upload is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},"description":"The Word documents of a `word` import, in their order. Empty for other imports."},"options":{"type":"object","properties":{"spaceKey":{"description":"Key of the Confluence space read through the API or from a site backup.","type":"string"},"pageIds":{"description":"IDs of the top-level pages whose trees are imported; all pages when left out.","type":"array","items":{"type":"string"}},"blogPosts":{"description":"Whether blog posts are imported; true when left out.","type":"boolean"},"split":{"type":"string","description":"`file` makes each Word document one page, `heading` adds a subpage per top-level heading. New values can be added in later versions; handle unknown values.","x-extensible-enum":["file","heading"]},"knowledgeBase":{"description":"For a `markdown` import: whether the new space is a knowledge base.","type":"boolean"}},"additionalProperties":false,"description":"Options of the source."},"throttledUntil":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Until when Confluence asked Lunedo to slow down, or null. The import continues by itself. ISO 8601 timestamp in UTC."},"waitingFor":{"description":"Key of the Confluence space whose import over the same connection reads or runs first, or null. Imports sharing a connection run one after another; this one continues by itself.","type":["string","null"]},"tokenDeletedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the API token was deleted: when the import was accepted, discarded, stopped or failed, when the importer lost the permission to import, or when the draft was left alone for a week. ISO 8601 timestamp in UTC."},"sourceUrl":{"description":"Address of the Confluence site. Links to pages outside the export point there.","type":["string","null"]},"reviewers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"People who can read the quarantine space and the report."},"phase":{"anyOf":[{"type":"string","x-extensible-enum":["read","compare","space","people","pages","attachments","templates","content","comments","reactions","permissions","baseline","finish","lineage","moves","labels","deletions","done"]},{"type":"null"}],"description":"Step the import is in: `read` reads the export, then `space`, `people`, `pages`, `attachments`, `templates`, `content`, `comments`, `reactions`, `permissions`, `baseline` and `finish`; `done` after the last step. A re-import compares in `compare` and applies in `lineage`, `people`, `pages`, `moves`, `attachments`, `templates`, `content`, `labels`, `comments`, `reactions`, `deletions`, `baseline` and `finish`. New values can be added in later versions; handle unknown values."},"progress":{"type":"object","properties":{"done":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units done in the current step."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units of the current step, or 0 when not known."}},"required":["done","total"],"additionalProperties":false,"description":"Progress of the current step."},"found":{"anyOf":[{"type":"object","properties":{"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages in the export."},"blogPosts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Blog posts in the export."},"versions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Earlier versions of pages and blog posts."},"comments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Comments, including inline comments and replies."},"likes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Likes on pages, blog posts and comments."},"watchers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Watchers of pages and the space. They are counted, not imported."},"attachments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Attachments of these pages."},"attachmentBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the current attachment versions in bytes."},"people":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"People named in the export."},"macroKinds":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Different macros used on the pages."},"spaceKey":{"type":"string","description":"Key of the space in Confluence."},"spaceName":{"type":"string","description":"Name of the space in Confluence."}},"required":["pages","blogPosts","versions","comments","likes","watchers","attachments","attachmentBytes","people","macroKinds","spaceKey","spaceName"],"additionalProperties":false},{"type":"null"}],"description":"What the export contains, once it was read."},"sourceSpaces":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the space in Confluence."},"name":{"type":"string","description":"Name of the space in Confluence."}},"required":["key","name"],"additionalProperties":false}},{"type":"null"}],"description":"The spaces of a site backup, once it was read; choose one with `options.spaceKey`. Null for exports and backups of one space."},"counts":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"What was imported, by kind: `pages`, `blogPosts`, `versions`, `attachments`, `attachmentVersions`, `comments`, `inlineAnchored`, `inlineMoved`, `likes`, `watchers`, `people`, `peopleMatched`, `restrictions`, `groupsMissing` and `problems`."},"errorCode":{"description":"Why the export could not be read or the import failed, such as `notAnArchive`, `wrongFormat`, `archiveTooLarge`, `unsafeEntryName`, `xmlDeclaration`, `spaceChoiceRequired` (a site backup with several spaces; see `sourceSpaces`) or `internalError`.","type":["string","null"]},"quarantineSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."}},"required":["id","key"],"additionalProperties":false},{"type":"null"}],"description":"The space the import writes into."},"targetSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"name":{"type":"string","description":"Name of the space."}},"required":["id","key","name"],"additionalProperties":false},{"type":"null"}],"description":"For a re-import, the space created by the earlier import that the changes go into; otherwise null."},"reimportSpaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space a newer export of the same Confluence space can be imported into again, or null when this import offers no re-import."},"canManage":{"type":"boolean","description":"Whether the caller can change, start, stop, accept or discard the import."},"canResolve":{"type":"boolean","description":"Whether the caller can map people and groups of the import or apply a user list."},"canTakeOver":{"type":"boolean","description":"Whether the caller can take over a held import."},"startedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import finished or failed. ISO 8601 timestamp in UTC."},"decidedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import was accepted, discarded or stopped. ISO 8601 timestamp in UTC."},"fileExpiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When an uploaded file is deleted. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the import was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the import last changed. ISO 8601 timestamp in UTC."}},"required":["id","organizationId","importer","source","state","draftStep","file","spaceName","spaceKey","archived","history","peopleSource","connection","files","options","throttledUntil","waitingFor","tokenDeletedAt","sourceUrl","reviewers","phase","progress","found","sourceSpaces","counts","errorCode","quarantineSpace","targetSpace","reimportSpaceId","canManage","canResolve","canTakeOver","startedAt","finishedAt","decidedAt","fileExpiresAt","createdAt","updatedAt"],"additionalProperties":false,"description":"An import of a Confluence space."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0001","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0002","importer":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0003","name":"Alex Admin"},"source":"confluence-xml","state":"review","draftStep":3,"file":{"kind":"upload","name":"export.zip","size":1048576,"uploadId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0004","complete":true},"spaceName":"IT Operations","spaceKey":"ITOPS","archived":false,"sourceUrl":"https://example.atlassian.net/wiki","reviewers":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0005","name":"Robin Reviewer"}],"phase":null,"progress":{"done":0,"total":0},"found":{"pages":120,"blogPosts":6,"versions":340,"comments":85,"likes":30,"watchers":44,"attachments":40,"attachmentBytes":2048000,"people":12,"macroKinds":6,"spaceKey":"ITOPS","spaceName":"IT Operations"},"sourceSpaces":null,"history":false,"peopleSource":{"kind":"token","site":"example.atlassian.net","email":"alex@example.com","people":12,"withEmail":10},"connection":null,"files":[],"options":{},"throttledUntil":null,"waitingFor":null,"tokenDeletedAt":null,"counts":{"pages":120,"blogPosts":6,"attachments":40,"attachmentVersions":52,"comments":85,"people":12,"problems":7},"errorCode":null,"quarantineSpace":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0006","key":"ITOPS"},"targetSpace":null,"reimportSpaceId":null,"canManage":true,"canResolve":true,"canTakeOver":false,"startedAt":"2026-10-10T08:00:00.000Z","finishedAt":"2026-10-10T08:05:00.000Z","decidedAt":null,"fileExpiresAt":null,"createdAt":"2026-10-10T07:50:00.000Z","updatedAt":"2026-10-10T08:05:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `userListInvalid`: The file is not a user list from Atlassian.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"userListInvalid":{"value":{"type":"urn:lunedo:problem:userListInvalid","title":"The file is not a user list from Atlassian","status":400,"code":"userListInvalid"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`importStarted`: The import has started.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"importStarted":{"value":{"type":"urn:lunedo:problem:importStarted","title":"The import has started","status":409,"code":"importStarted"}}}}}},"413":{"description":"`userListTooLarge`: The user list is too large.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"userListTooLarge":{"value":{"type":"urn:lunedo:problem:userListTooLarge","title":"The user list is too large","status":413,"code":"userListTooLarge"}}}}}},"415":{"description":"`unsupportedMediaType`: The request body has an unsupported type.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unsupportedMediaType":{"value":{"type":"urn:lunedo:problem:unsupportedMediaType","title":"The request body has an unsupported type","status":415,"code":"unsupportedMediaType"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/imports/{importId}/people/mappings":{"post":{"operationId":"imports.mapPeople","summary":"Map placeholders to accounts","description":"Maps one or more placeholders to accounts of the organization. Authorship, comments, mentions, tasks, reactions and places on page restrictions move to the account in one step. Before accepting, only the person who started the import can map; after accepting, every organization administrator who manages imports. Roles the person had in the Confluence space apply when the import is accepted. Nobody is notified. A mapping cannot be undone. A placeholder that holds access to pages or the space cannot be mapped to the caller's own account.\n\nRequires the permission `import.resolve` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.resolve","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mappings":{"minItems":1,"maxItems":100,"type":"array","items":{"type":"object","properties":{"placeholderId":{"type":"string","format":"uuid","description":"ID of the placeholder."},"accountId":{"type":"string","format":"uuid","description":"ID of an active member of the organization."}},"required":["placeholderId","accountId"],"additionalProperties":false},"description":"Placeholders and the accounts they become. All are applied together or none."}},"required":["mappings"],"additionalProperties":false,"description":"Mappings of placeholders to accounts."},"example":{"mappings":[{"placeholderId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0001","accountId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0003"}]}}}},"responses":{"200":{"description":"How many placeholders were mapped.","content":{"application/json":{"schema":{"type":"object","properties":{"mapped":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of mapped placeholders."}},"required":["mapped"],"additionalProperties":false,"description":"Result."},"example":{"mapped":1}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidMapping`: The mapping is not valid. `invalidMappingTarget`: The account cannot take over the placeholder.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidMapping":{"value":{"type":"urn:lunedo:problem:invalidMapping","title":"The mapping is not valid","status":400,"code":"invalidMapping"}},"invalidMappingTarget":{"value":{"type":"urn:lunedo:problem:invalidMappingTarget","title":"The account cannot take over the placeholder","status":400,"code":"invalidMappingTarget"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `selfExtension`: Nobody can extend their own permissions.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"selfExtension":{"value":{"type":"urn:lunedo:problem:selfExtension","title":"Nobody can extend their own permissions","status":403,"code":"selfExtension"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`importNotResolvable`: People and groups can be mapped once the import has finished. `notPlaceholder`: The account is not a placeholder that can be merged.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"importNotResolvable":{"value":{"type":"urn:lunedo:problem:importNotResolvable","title":"People and groups can be mapped once the import has finished","status":409,"code":"importNotResolvable"}},"notPlaceholder":{"value":{"type":"urn:lunedo:problem:notPlaceholder","title":"The account is not a placeholder that can be merged","status":409,"code":"notPlaceholder"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/imports/{importId}/people/user-list":{"post":{"operationId":"imports.userList","summary":"Resolve placeholders with a user list","description":"Reads a user list exported from the Atlassian administration and maps every remaining placeholder whose e-mail address belongs to a member of the organization. Placeholders without a match get the name from the list. Works before and after accepting, with the same permission as mapping placeholders. Send the CSV with `Content-Type: text/csv`, up to 10 MB.\n\nRequires the permission `import.resolve` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.resolve","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"description":"The user list as CSV with a header row.","content":{"text/csv":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"What the list resolved.","content":{"application/json":{"schema":{"type":"object","properties":{"matched":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Placeholders mapped by e-mail address."},"named":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Placeholders that got a name from the list."},"remaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Placeholders that remain."}},"required":["matched","named","remaining"],"additionalProperties":false,"description":"What a user list resolved."},"example":{"matched":9,"named":3,"remaining":4}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `userListInvalid`: The file is not a user list from Atlassian.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"userListInvalid":{"value":{"type":"urn:lunedo:problem:userListInvalid","title":"The file is not a user list from Atlassian","status":400,"code":"userListInvalid"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`importNotResolvable`: People and groups can be mapped once the import has finished.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"importNotResolvable":{"value":{"type":"urn:lunedo:problem:importNotResolvable","title":"People and groups can be mapped once the import has finished","status":409,"code":"importNotResolvable"}}}}}},"413":{"description":"`userListTooLarge`: The user list is too large.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"userListTooLarge":{"value":{"type":"urn:lunedo:problem:userListTooLarge","title":"The user list is too large","status":413,"code":"userListTooLarge"}}}}}},"415":{"description":"`unsupportedMediaType`: The request body has an unsupported type.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unsupportedMediaType":{"value":{"type":"urn:lunedo:problem:unsupportedMediaType","title":"The request body has an unsupported type","status":415,"code":"unsupportedMediaType"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/imports/{importId}/permissions":{"get":{"operationId":"imports.permissions","summary":"List the permissions of an import","description":"Lists the space permissions and page restrictions taken from Confluence: the role each person or group gets, and the entries that need attention. Anonymous access is never taken over. Titles of pages the caller cannot read are left out.\n\nRequires the permission `import.view` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.view","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"A page of entries.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the entry."},"scope":{"type":"string","description":"Whether the entry is a space permission or a page restriction. New values can be added in later versions; handle unknown values.","x-extensible-enum":["space","page"]},"item":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the page."},"title":{"description":"Title of the page, or null when the caller cannot read it.","type":["string","null"]}},"required":["id","title"],"additionalProperties":false},{"type":"null"}],"description":"The restricted page, or null for space permissions."},"restriction":{"anyOf":[{"type":"string","x-extensible-enum":["view","edit"]},{"type":"null"}],"description":"Kind of page restriction. New values can be added in later versions; handle unknown values."},"holder":{"type":"object","properties":{"kind":{"type":"string","description":"Who held the permission: a person, a group, all signed-in users or anonymous visitors. New values can be added in later versions; handle unknown values.","x-extensible-enum":["account","group","organizationMembers","anonymous"]},"id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the account or group in Lunedo."},"name":{"description":"Name in Lunedo, or null.","type":["string","null"]},"sourceName":{"description":"Name of the group in Confluence, or null.","type":["string","null"]}},"required":["kind","id","name","sourceName"],"additionalProperties":false,"description":"The holder of the permission."},"role":{"anyOf":[{"type":"string","description":"Role in the space: `reader`, `commenter`, `editor` or `admin` (space admin). New values can be added in later versions; handle unknown values.","x-extensible-enum":["reader","commenter","editor","admin"]},{"type":"null"}],"description":"Role in Lunedo, or null when nothing is taken over."},"permissions":{"type":"array","items":{"type":"string"},"description":"Confluence permissions of the holder, such as `VIEWSPACE`."},"status":{"type":"string","description":"`mapped` fits exactly, `check` differs from Confluence, `missing` waits for a group, `waiting` waits for a person to be mapped, `notTaken` is not taken over. New values can be added in later versions; handle unknown values.","x-extensible-enum":["mapped","check","missing","notTaken","waiting"]},"code":{"description":"Why the entry needs attention: `widened`, `narrowed`, `withoutView`, `anonymous`, `app` (an app account, not a person), `groupMissing`, `placeholder` or `withoutSpaceRole` (named in a restriction without a role in the space).","type":["string","null"]}},"required":["id","scope","item","restriction","holder","role","permissions","status","code"],"additionalProperties":false,"description":"A permission taken from Confluence."},"description":"Permission entries in the order they were found."},"nextCursor":{"description":"Cursor of the next page, or null on the last page.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"Permissions of the import."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0001","scope":"space","item":null,"restriction":null,"holder":{"kind":"group","id":null,"name":null,"sourceName":"contractors"},"role":"reader","permissions":["VIEWSPACE"],"status":"missing","code":"groupMissing"}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`reportUnavailable`: The report is not available yet.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"reportUnavailable":{"value":{"type":"urn:lunedo:problem:reportUnavailable","title":"The report is not available yet","status":409,"code":"reportUnavailable"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/imports/{importId}/proposed-access":{"get":{"operationId":"imports.proposedAccess","summary":"Get the imported access","description":"Returns who gets access when the import is accepted, as taken from Confluence. The accept dialog shows it instead of the organization defaults, and the administrator can change it before accepting.\n\nRequires the permission `import.view` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.view","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The imported access.","content":{"application/json":{"schema":{"type":"object","properties":{"visibility":{"type":"string","enum":["private","organization","instance"],"description":"Who can read the space besides its holders: `private` (only holders), `organization` (every member of the organization) or `instance` (every internal user of the instance)."},"grants":{"type":"array","items":{"type":"object","properties":{"principalKind":{"type":"string","enum":["account","group","organizationMembers","instanceUsers"],"description":"Holder of a role: an account (person or service account), a group, all members of the organization, or all internal users of the instance."},"principalId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the account or group; null for all members and all internal users."},"role":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},"name":{"description":"Name of the person or group, or null.","type":["string","null"]}},"required":["principalKind","principalId","role","name"],"additionalProperties":false,"description":"A role for a holder, with the holder's name."},"description":"Roles taken from Confluence for people and groups that exist in Lunedo."},"pending":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Imported roles that wait for a person or group to be mapped; they apply when it is mapped."}},"required":["visibility","grants","pending"],"additionalProperties":false,"description":"Who gets access when the import is accepted, as imported from Confluence."},"example":{"visibility":"organization","grants":[{"principalKind":"organizationMembers","principalId":null,"role":"commenter","name":null}],"pending":2}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`reportUnavailable`: The report is not available yet.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"reportUnavailable":{"value":{"type":"urn:lunedo:problem:reportUnavailable","title":"The report is not available yet","status":409,"code":"reportUnavailable"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/imports/{importId}/report":{"get":{"operationId":"imports.report","summary":"Get the report of an import","description":"Counts the report entries per kind.\n\nRequires the permission `import.view` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.view","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The summary.","content":{"application/json":{"schema":{"type":"object","properties":{"categories":{"type":"array","items":{"type":"object","properties":{"category":{"type":"string","description":"Area of the problem: `macros`, `attachments`, `links`, `content`, `comments` or `archive`. New values can be added in later versions; handle unknown values.","x-extensible-enum":["macros","diagrams","attachments","links","content","comments","archive","source"]},"code":{"type":"string","description":"Kind of problem. New values can be added in later versions; handle unknown values.","x-extensible-enum":["unsupportedMacro","unmappedQuery","macroOptionDropped","chartNotImported","jiraNotImported","diagramFileMissing","gliffyDiagram","diagramPageMissing","previewOnly","previewMissing","missingAttachment","attachmentFileMissing","attachmentTooLarge","attachmentUnreadable","externalPageLink","unsupportedLink","invalidLink","externalImage","unresolvedInclude","embedNotAllowed","invalidContent","contentTruncated","macroDataTruncated","unresolvedPerson","invalidLabel","inlineCommentMoved","tooManyComments","duplicateEntry","skippedEntry","contentSkipped","trashedContent","removedRestrictionKept","restrictionsUnreadable","pageUnreadable","listingIncomplete","contentTypeNotImported","likesAndWatchersSkipped","permissionsUnavailable","unsupportedMarkdown","unresolvedFileLink","embeddedObject","wordCommentsDropped","unreadableImage","documentTooLarge","translationNotImported"]},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of entries."}},"required":["category","code","count"],"additionalProperties":false,"description":"Entries of one kind."},"description":"Entries per kind."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of all entries."},"placeholders":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"People who are still placeholders."},"mapped":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Placeholders mapped to accounts."},"permissionsToCheck":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Permission entries that did not map exactly or wait for a person or group."},"groupsMissing":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Confluence groups without a group in Lunedo."}},"required":["categories","total","placeholders","mapped","permissionsToCheck","groupsMissing"],"additionalProperties":false,"description":"Summary of the report of an import."},"example":{"categories":[{"category":"macros","code":"unsupportedMacro","count":3}],"total":3,"placeholders":13,"mapped":2,"permissionsToCheck":6,"groupsMissing":1}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`reportUnavailable`: The report is not available yet.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"reportUnavailable":{"value":{"type":"urn:lunedo:problem:reportUnavailable","title":"The report is not available yet","status":409,"code":"reportUnavailable"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/imports/{importId}/report/entries":{"get":{"operationId":"imports.entries","summary":"List report entries","description":"Lists the problems found during the import, each with the affected page.\n\nRequires the permission `import.view` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.view","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}},{"name":"category","in":"query","required":false,"description":"Only entries of this area, such as `attachments`.","schema":{"type":"string","maxLength":50}},{"name":"code","in":"query","required":false,"description":"Only entries of this kind, such as `externalPageLink`.","schema":{"type":"string","maxLength":50}},{"name":"macro","in":"query","required":false,"description":"Only pages that use the macro with this name.","schema":{"type":"string","maxLength":200}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"A page of entries.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the entry."},"category":{"type":"string","description":"Area of the problem."},"code":{"type":"string","description":"Kind of problem."},"item":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the page."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the page in the addresses of the app."},"title":{"type":"string","description":"Title of the page."}},"required":["id","number","title"],"additionalProperties":false},{"type":"null"}],"description":"The affected page, or null when the problem concerns the export as a whole or a page the caller cannot read."},"restricted":{"type":"boolean","description":"True when the problem concerns a page the caller cannot read; `item` is then null."},"template":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space template."},"name":{"type":"string","description":"Name of the space template."}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"The affected space template, or null when the problem concerns a page or the export."},"details":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Facts of the problem, such as `name` of a macro or `fileName` of an attachment."}},"required":["id","category","code","item","restricted","template","details"],"additionalProperties":false,"description":"A report entry."},"description":"Entries in the order they were found."},"nextCursor":{"description":"Cursor of the next page, or null on the last page.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"A page of report entries."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0001","category":"attachments","code":"missingAttachment","item":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0002","number":1031,"title":"Network overview"},"restricted":false,"template":null,"details":{"fileName":"diagram.png"}}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`reportUnavailable`: The report is not available yet.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"reportUnavailable":{"value":{"type":"urn:lunedo:problem:reportUnavailable","title":"The report is not available yet","status":409,"code":"reportUnavailable"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/imports/{importId}/report/export":{"get":{"operationId":"imports.exportReport","summary":"Export the report as CSV","description":"Streams all report entries as CSV. Cells that start with a formula character are prefixed with an apostrophe.\n\nRequires the permission `import.view` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.view","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The entries as CSV with a header row.","content":{"text/csv":{"schema":{"type":"string"},"example":"\"category\",\"code\",\"page\",\"details\"\r\n\"macros\",\"unsupportedMacro\",\"Alpha\",\"{\"\"name\"\":\"\"info\"\",\"\"count\"\":1}\"\r\n"}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`reportUnavailable`: The report is not available yet.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"reportUnavailable":{"value":{"type":"urn:lunedo:problem:reportUnavailable","title":"The report is not available yet","status":409,"code":"reportUnavailable"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/imports/{importId}/report/macros":{"get":{"operationId":"imports.macros","summary":"List the macros of an import","description":"Lists the macros kept with their original data, with the number of pages that use them.\n\nRequires the permission `import.view` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.view","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The macros.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the macro in Confluence."},"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of pages that use it."},"occurrences":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of uses."}},"required":["name","pages","occurrences"],"additionalProperties":false,"description":"A macro that is not converted yet."},"description":"Macros kept with their original data, most used first."},"example":[{"name":"info","pages":12,"occurrences":30}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`reportUnavailable`: The report is not available yet.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"reportUnavailable":{"value":{"type":"urn:lunedo:problem:reportUnavailable","title":"The report is not available yet","status":409,"code":"reportUnavailable"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/imports/{importId}/reviewers":{"put":{"operationId":"imports.reviewers","summary":"Set the reviewers of an import","description":"Replaces the reviewers. Reviewers can read the quarantine space and the report, but cannot accept, discard or stop the import. The change is audited.\n\nRequires the permission `import.manage` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.manage","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"accountIds":{"maxItems":50,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a member of the organization."},"description":"All reviewers. People who are left out lose access to the quarantine space at once."}},"required":["accountIds"],"additionalProperties":false,"description":"The reviewers of an import."},"example":{"accountIds":["01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0005"]}}}},"responses":{"200":{"description":"The import.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the import."},"organizationId":{"type":"string","format":"uuid","description":"Organization the import belongs to."},"importer":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"The administrator who imports."},"source":{"type":"string","description":"What is imported: `confluence-xml` for the XML space export of Confluence Cloud or Data Center, `confluence-csv` for the CSV space export of Confluence Cloud, `confluence-cloud` and `confluence-dc` to read a space through the Confluence API, `markdown` for a ZIP file of Markdown files, `word` for Word documents (`.docx`). New values can be added in later versions; handle unknown values.","x-extensible-enum":["confluence-xml","confluence-csv","confluence-cloud","confluence-dc","markdown","word"]},"state":{"type":"string","description":"State of the import. `draft` while the wizard is filled in, `analyzing` while the export is read, `ready` when it can be started, `running` while it imports, `held` when the importing administrator lost the permission and another administrator has to take over, `stopping` and `discarding` while the quarantine space is deleted, `review` when the quarantine space waits for a decision, `accepted`, `discarded`, `stopped` and `failed` at the end. A re-import is in `running` while it compares or applies, in `review` while changes wait for a decision, `accepted` when everything is applied, and `superseded` when a newer re-import of the same space replaced it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["draft","analyzing","ready","running","held","stopping","review","accepting","accepted","discarding","discarded","stopped","failed","superseded"]},"draftStep":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Step of the wizard the importer was on, for continuing a draft."},"file":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Where the export comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload","folder"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes, or null when not known yet."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload, or null for a file in the import folder."},"complete":{"type":"boolean","description":"Whether the file is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},{"type":"null"}],"description":"The export file, or null when none is chosen yet."},"spaceName":{"description":"Name of the new space.","type":["string","null"]},"spaceKey":{"description":"Key of the new space.","type":["string","null"]},"archived":{"type":"boolean","description":"Whether the space becomes archived when the import is accepted."},"history":{"type":"boolean","description":"Whether every Confluence version becomes a Lunedo version, or only the current state is imported."},"peopleSource":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"How people are recognized: `token` reads names and e-mail addresses with a read-only Atlassian API token, `list` uses a user list exported from the Atlassian administration, `skip` keeps every author as a placeholder, `source` takes the names Confluence Data Center returns through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["token","list","skip","source"]},"site":{"description":"Confluence site the token is used with, or null.","type":["string","null"]},"email":{"description":"Atlassian e-mail address the token belongs to, or null.","type":["string","null"]},"people":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"People of the export the token could read, or people in the user list; null when unknown."},"withEmail":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Of these, people with a visible e-mail address."}},"required":["kind","site","email","people","withEmail"],"additionalProperties":false},{"type":"null"}],"description":"How people are recognized. The token itself is never returned."},"connection":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Kind of Confluence the import reads through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["cloud","dataCenter"]},"site":{"type":"string","description":"Host name of the Confluence site, with the port when it is not 443."},"basePath":{"type":"string","description":"Context path of Confluence Data Center, such as `/confluence`, or empty."},"email":{"description":"Atlassian e-mail address the API token belongs to, or null.","type":["string","null"]},"account":{"description":"Name of the Confluence account the token belongs to.","type":["string","null"]},"selection":{"type":"array","items":{"type":"object","properties":{"importId":{"type":"string","format":"uuid","description":"ID of the import that reads the space."},"spaceKey":{"type":"string","description":"Key of the Confluence space."}},"required":["importId","spaceKey"],"additionalProperties":false},"description":"Spaces chosen with this connection whose imports are not started yet, one import per space, this import included. Empty once the import has started."}},"required":["kind","site","basePath","email","account","selection"],"additionalProperties":false},{"type":"null"}],"description":"The connection of an import through the Confluence API, or null. Several imports of the same importer can share one connection; the token is never returned."},"files":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","description":"Where the document comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload."},"complete":{"type":"boolean","description":"Whether the upload is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},"description":"The Word documents of a `word` import, in their order. Empty for other imports."},"options":{"type":"object","properties":{"spaceKey":{"description":"Key of the Confluence space read through the API or from a site backup.","type":"string"},"pageIds":{"description":"IDs of the top-level pages whose trees are imported; all pages when left out.","type":"array","items":{"type":"string"}},"blogPosts":{"description":"Whether blog posts are imported; true when left out.","type":"boolean"},"split":{"type":"string","description":"`file` makes each Word document one page, `heading` adds a subpage per top-level heading. New values can be added in later versions; handle unknown values.","x-extensible-enum":["file","heading"]},"knowledgeBase":{"description":"For a `markdown` import: whether the new space is a knowledge base.","type":"boolean"}},"additionalProperties":false,"description":"Options of the source."},"throttledUntil":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Until when Confluence asked Lunedo to slow down, or null. The import continues by itself. ISO 8601 timestamp in UTC."},"waitingFor":{"description":"Key of the Confluence space whose import over the same connection reads or runs first, or null. Imports sharing a connection run one after another; this one continues by itself.","type":["string","null"]},"tokenDeletedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the API token was deleted: when the import was accepted, discarded, stopped or failed, when the importer lost the permission to import, or when the draft was left alone for a week. ISO 8601 timestamp in UTC."},"sourceUrl":{"description":"Address of the Confluence site. Links to pages outside the export point there.","type":["string","null"]},"reviewers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"People who can read the quarantine space and the report."},"phase":{"anyOf":[{"type":"string","x-extensible-enum":["read","compare","space","people","pages","attachments","templates","content","comments","reactions","permissions","baseline","finish","lineage","moves","labels","deletions","done"]},{"type":"null"}],"description":"Step the import is in: `read` reads the export, then `space`, `people`, `pages`, `attachments`, `templates`, `content`, `comments`, `reactions`, `permissions`, `baseline` and `finish`; `done` after the last step. A re-import compares in `compare` and applies in `lineage`, `people`, `pages`, `moves`, `attachments`, `templates`, `content`, `labels`, `comments`, `reactions`, `deletions`, `baseline` and `finish`. New values can be added in later versions; handle unknown values."},"progress":{"type":"object","properties":{"done":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units done in the current step."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units of the current step, or 0 when not known."}},"required":["done","total"],"additionalProperties":false,"description":"Progress of the current step."},"found":{"anyOf":[{"type":"object","properties":{"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages in the export."},"blogPosts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Blog posts in the export."},"versions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Earlier versions of pages and blog posts."},"comments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Comments, including inline comments and replies."},"likes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Likes on pages, blog posts and comments."},"watchers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Watchers of pages and the space. They are counted, not imported."},"attachments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Attachments of these pages."},"attachmentBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the current attachment versions in bytes."},"people":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"People named in the export."},"macroKinds":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Different macros used on the pages."},"spaceKey":{"type":"string","description":"Key of the space in Confluence."},"spaceName":{"type":"string","description":"Name of the space in Confluence."}},"required":["pages","blogPosts","versions","comments","likes","watchers","attachments","attachmentBytes","people","macroKinds","spaceKey","spaceName"],"additionalProperties":false},{"type":"null"}],"description":"What the export contains, once it was read."},"sourceSpaces":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the space in Confluence."},"name":{"type":"string","description":"Name of the space in Confluence."}},"required":["key","name"],"additionalProperties":false}},{"type":"null"}],"description":"The spaces of a site backup, once it was read; choose one with `options.spaceKey`. Null for exports and backups of one space."},"counts":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"What was imported, by kind: `pages`, `blogPosts`, `versions`, `attachments`, `attachmentVersions`, `comments`, `inlineAnchored`, `inlineMoved`, `likes`, `watchers`, `people`, `peopleMatched`, `restrictions`, `groupsMissing` and `problems`."},"errorCode":{"description":"Why the export could not be read or the import failed, such as `notAnArchive`, `wrongFormat`, `archiveTooLarge`, `unsafeEntryName`, `xmlDeclaration`, `spaceChoiceRequired` (a site backup with several spaces; see `sourceSpaces`) or `internalError`.","type":["string","null"]},"quarantineSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."}},"required":["id","key"],"additionalProperties":false},{"type":"null"}],"description":"The space the import writes into."},"targetSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"name":{"type":"string","description":"Name of the space."}},"required":["id","key","name"],"additionalProperties":false},{"type":"null"}],"description":"For a re-import, the space created by the earlier import that the changes go into; otherwise null."},"reimportSpaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space a newer export of the same Confluence space can be imported into again, or null when this import offers no re-import."},"canManage":{"type":"boolean","description":"Whether the caller can change, start, stop, accept or discard the import."},"canResolve":{"type":"boolean","description":"Whether the caller can map people and groups of the import or apply a user list."},"canTakeOver":{"type":"boolean","description":"Whether the caller can take over a held import."},"startedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import finished or failed. ISO 8601 timestamp in UTC."},"decidedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import was accepted, discarded or stopped. ISO 8601 timestamp in UTC."},"fileExpiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When an uploaded file is deleted. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the import was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the import last changed. ISO 8601 timestamp in UTC."}},"required":["id","organizationId","importer","source","state","draftStep","file","spaceName","spaceKey","archived","history","peopleSource","connection","files","options","throttledUntil","waitingFor","tokenDeletedAt","sourceUrl","reviewers","phase","progress","found","sourceSpaces","counts","errorCode","quarantineSpace","targetSpace","reimportSpaceId","canManage","canResolve","canTakeOver","startedAt","finishedAt","decidedAt","fileExpiresAt","createdAt","updatedAt"],"additionalProperties":false,"description":"An import of a Confluence space."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0001","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0002","importer":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0003","name":"Alex Admin"},"source":"confluence-xml","state":"review","draftStep":3,"file":{"kind":"upload","name":"export.zip","size":1048576,"uploadId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0004","complete":true},"spaceName":"IT Operations","spaceKey":"ITOPS","archived":false,"sourceUrl":"https://example.atlassian.net/wiki","reviewers":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0005","name":"Robin Reviewer"}],"phase":null,"progress":{"done":0,"total":0},"found":{"pages":120,"blogPosts":6,"versions":340,"comments":85,"likes":30,"watchers":44,"attachments":40,"attachmentBytes":2048000,"people":12,"macroKinds":6,"spaceKey":"ITOPS","spaceName":"IT Operations"},"sourceSpaces":null,"history":false,"peopleSource":{"kind":"token","site":"example.atlassian.net","email":"alex@example.com","people":12,"withEmail":10},"connection":null,"files":[],"options":{},"throttledUntil":null,"waitingFor":null,"tokenDeletedAt":null,"counts":{"pages":120,"blogPosts":6,"attachments":40,"attachmentVersions":52,"comments":85,"people":12,"problems":7},"errorCode":null,"quarantineSpace":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0006","key":"ITOPS"},"targetSpace":null,"reimportSpaceId":null,"canManage":true,"canResolve":true,"canTakeOver":false,"startedAt":"2026-10-10T08:00:00.000Z","finishedAt":"2026-10-10T08:05:00.000Z","decidedAt":null,"fileExpiresAt":null,"createdAt":"2026-10-10T07:50:00.000Z","updatedAt":"2026-10-10T08:05:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidReviewer`: The reviewer is not valid. `tooManyReviewers`: The import has too many reviewers.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidReviewer":{"value":{"type":"urn:lunedo:problem:invalidReviewer","title":"The reviewer is not valid","status":400,"code":"invalidReviewer"}},"tooManyReviewers":{"value":{"type":"urn:lunedo:problem:tooManyReviewers","title":"The import has too many reviewers","status":400,"code":"tooManyReviewers"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`importFinished`: The import is finished.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"importFinished":{"value":{"type":"urn:lunedo:problem:importFinished","title":"The import is finished","status":409,"code":"importFinished"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/imports/{importId}/start":{"post":{"operationId":"imports.start","summary":"Start an import","description":"Creates the quarantine space and starts importing in the background. Only the importing administrator and the reviewers can see the space until the import is accepted.\n\nRequires the permission `import.manage` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.manage","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The import.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the import."},"organizationId":{"type":"string","format":"uuid","description":"Organization the import belongs to."},"importer":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"The administrator who imports."},"source":{"type":"string","description":"What is imported: `confluence-xml` for the XML space export of Confluence Cloud or Data Center, `confluence-csv` for the CSV space export of Confluence Cloud, `confluence-cloud` and `confluence-dc` to read a space through the Confluence API, `markdown` for a ZIP file of Markdown files, `word` for Word documents (`.docx`). New values can be added in later versions; handle unknown values.","x-extensible-enum":["confluence-xml","confluence-csv","confluence-cloud","confluence-dc","markdown","word"]},"state":{"type":"string","description":"State of the import. `draft` while the wizard is filled in, `analyzing` while the export is read, `ready` when it can be started, `running` while it imports, `held` when the importing administrator lost the permission and another administrator has to take over, `stopping` and `discarding` while the quarantine space is deleted, `review` when the quarantine space waits for a decision, `accepted`, `discarded`, `stopped` and `failed` at the end. A re-import is in `running` while it compares or applies, in `review` while changes wait for a decision, `accepted` when everything is applied, and `superseded` when a newer re-import of the same space replaced it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["draft","analyzing","ready","running","held","stopping","review","accepting","accepted","discarding","discarded","stopped","failed","superseded"]},"draftStep":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Step of the wizard the importer was on, for continuing a draft."},"file":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Where the export comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload","folder"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes, or null when not known yet."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload, or null for a file in the import folder."},"complete":{"type":"boolean","description":"Whether the file is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},{"type":"null"}],"description":"The export file, or null when none is chosen yet."},"spaceName":{"description":"Name of the new space.","type":["string","null"]},"spaceKey":{"description":"Key of the new space.","type":["string","null"]},"archived":{"type":"boolean","description":"Whether the space becomes archived when the import is accepted."},"history":{"type":"boolean","description":"Whether every Confluence version becomes a Lunedo version, or only the current state is imported."},"peopleSource":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"How people are recognized: `token` reads names and e-mail addresses with a read-only Atlassian API token, `list` uses a user list exported from the Atlassian administration, `skip` keeps every author as a placeholder, `source` takes the names Confluence Data Center returns through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["token","list","skip","source"]},"site":{"description":"Confluence site the token is used with, or null.","type":["string","null"]},"email":{"description":"Atlassian e-mail address the token belongs to, or null.","type":["string","null"]},"people":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"People of the export the token could read, or people in the user list; null when unknown."},"withEmail":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Of these, people with a visible e-mail address."}},"required":["kind","site","email","people","withEmail"],"additionalProperties":false},{"type":"null"}],"description":"How people are recognized. The token itself is never returned."},"connection":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Kind of Confluence the import reads through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["cloud","dataCenter"]},"site":{"type":"string","description":"Host name of the Confluence site, with the port when it is not 443."},"basePath":{"type":"string","description":"Context path of Confluence Data Center, such as `/confluence`, or empty."},"email":{"description":"Atlassian e-mail address the API token belongs to, or null.","type":["string","null"]},"account":{"description":"Name of the Confluence account the token belongs to.","type":["string","null"]},"selection":{"type":"array","items":{"type":"object","properties":{"importId":{"type":"string","format":"uuid","description":"ID of the import that reads the space."},"spaceKey":{"type":"string","description":"Key of the Confluence space."}},"required":["importId","spaceKey"],"additionalProperties":false},"description":"Spaces chosen with this connection whose imports are not started yet, one import per space, this import included. Empty once the import has started."}},"required":["kind","site","basePath","email","account","selection"],"additionalProperties":false},{"type":"null"}],"description":"The connection of an import through the Confluence API, or null. Several imports of the same importer can share one connection; the token is never returned."},"files":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","description":"Where the document comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload."},"complete":{"type":"boolean","description":"Whether the upload is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},"description":"The Word documents of a `word` import, in their order. Empty for other imports."},"options":{"type":"object","properties":{"spaceKey":{"description":"Key of the Confluence space read through the API or from a site backup.","type":"string"},"pageIds":{"description":"IDs of the top-level pages whose trees are imported; all pages when left out.","type":"array","items":{"type":"string"}},"blogPosts":{"description":"Whether blog posts are imported; true when left out.","type":"boolean"},"split":{"type":"string","description":"`file` makes each Word document one page, `heading` adds a subpage per top-level heading. New values can be added in later versions; handle unknown values.","x-extensible-enum":["file","heading"]},"knowledgeBase":{"description":"For a `markdown` import: whether the new space is a knowledge base.","type":"boolean"}},"additionalProperties":false,"description":"Options of the source."},"throttledUntil":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Until when Confluence asked Lunedo to slow down, or null. The import continues by itself. ISO 8601 timestamp in UTC."},"waitingFor":{"description":"Key of the Confluence space whose import over the same connection reads or runs first, or null. Imports sharing a connection run one after another; this one continues by itself.","type":["string","null"]},"tokenDeletedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the API token was deleted: when the import was accepted, discarded, stopped or failed, when the importer lost the permission to import, or when the draft was left alone for a week. ISO 8601 timestamp in UTC."},"sourceUrl":{"description":"Address of the Confluence site. Links to pages outside the export point there.","type":["string","null"]},"reviewers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"People who can read the quarantine space and the report."},"phase":{"anyOf":[{"type":"string","x-extensible-enum":["read","compare","space","people","pages","attachments","templates","content","comments","reactions","permissions","baseline","finish","lineage","moves","labels","deletions","done"]},{"type":"null"}],"description":"Step the import is in: `read` reads the export, then `space`, `people`, `pages`, `attachments`, `templates`, `content`, `comments`, `reactions`, `permissions`, `baseline` and `finish`; `done` after the last step. A re-import compares in `compare` and applies in `lineage`, `people`, `pages`, `moves`, `attachments`, `templates`, `content`, `labels`, `comments`, `reactions`, `deletions`, `baseline` and `finish`. New values can be added in later versions; handle unknown values."},"progress":{"type":"object","properties":{"done":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units done in the current step."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units of the current step, or 0 when not known."}},"required":["done","total"],"additionalProperties":false,"description":"Progress of the current step."},"found":{"anyOf":[{"type":"object","properties":{"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages in the export."},"blogPosts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Blog posts in the export."},"versions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Earlier versions of pages and blog posts."},"comments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Comments, including inline comments and replies."},"likes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Likes on pages, blog posts and comments."},"watchers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Watchers of pages and the space. They are counted, not imported."},"attachments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Attachments of these pages."},"attachmentBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the current attachment versions in bytes."},"people":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"People named in the export."},"macroKinds":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Different macros used on the pages."},"spaceKey":{"type":"string","description":"Key of the space in Confluence."},"spaceName":{"type":"string","description":"Name of the space in Confluence."}},"required":["pages","blogPosts","versions","comments","likes","watchers","attachments","attachmentBytes","people","macroKinds","spaceKey","spaceName"],"additionalProperties":false},{"type":"null"}],"description":"What the export contains, once it was read."},"sourceSpaces":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the space in Confluence."},"name":{"type":"string","description":"Name of the space in Confluence."}},"required":["key","name"],"additionalProperties":false}},{"type":"null"}],"description":"The spaces of a site backup, once it was read; choose one with `options.spaceKey`. Null for exports and backups of one space."},"counts":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"What was imported, by kind: `pages`, `blogPosts`, `versions`, `attachments`, `attachmentVersions`, `comments`, `inlineAnchored`, `inlineMoved`, `likes`, `watchers`, `people`, `peopleMatched`, `restrictions`, `groupsMissing` and `problems`."},"errorCode":{"description":"Why the export could not be read or the import failed, such as `notAnArchive`, `wrongFormat`, `archiveTooLarge`, `unsafeEntryName`, `xmlDeclaration`, `spaceChoiceRequired` (a site backup with several spaces; see `sourceSpaces`) or `internalError`.","type":["string","null"]},"quarantineSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."}},"required":["id","key"],"additionalProperties":false},{"type":"null"}],"description":"The space the import writes into."},"targetSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"name":{"type":"string","description":"Name of the space."}},"required":["id","key","name"],"additionalProperties":false},{"type":"null"}],"description":"For a re-import, the space created by the earlier import that the changes go into; otherwise null."},"reimportSpaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space a newer export of the same Confluence space can be imported into again, or null when this import offers no re-import."},"canManage":{"type":"boolean","description":"Whether the caller can change, start, stop, accept or discard the import."},"canResolve":{"type":"boolean","description":"Whether the caller can map people and groups of the import or apply a user list."},"canTakeOver":{"type":"boolean","description":"Whether the caller can take over a held import."},"startedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import finished or failed. ISO 8601 timestamp in UTC."},"decidedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import was accepted, discarded or stopped. ISO 8601 timestamp in UTC."},"fileExpiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When an uploaded file is deleted. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the import was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the import last changed. ISO 8601 timestamp in UTC."}},"required":["id","organizationId","importer","source","state","draftStep","file","spaceName","spaceKey","archived","history","peopleSource","connection","files","options","throttledUntil","waitingFor","tokenDeletedAt","sourceUrl","reviewers","phase","progress","found","sourceSpaces","counts","errorCode","quarantineSpace","targetSpace","reimportSpaceId","canManage","canResolve","canTakeOver","startedAt","finishedAt","decidedAt","fileExpiresAt","createdAt","updatedAt"],"additionalProperties":false,"description":"An import of a Confluence space."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0001","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0002","importer":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0003","name":"Alex Admin"},"source":"confluence-xml","state":"running","draftStep":3,"file":{"kind":"upload","name":"export.zip","size":1048576,"uploadId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0004","complete":true},"spaceName":"IT Operations","spaceKey":"ITOPS","archived":false,"sourceUrl":"https://example.atlassian.net/wiki","reviewers":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0005","name":"Robin Reviewer"}],"phase":null,"progress":{"done":0,"total":0},"found":{"pages":120,"blogPosts":6,"versions":340,"comments":85,"likes":30,"watchers":44,"attachments":40,"attachmentBytes":2048000,"people":12,"macroKinds":6,"spaceKey":"ITOPS","spaceName":"IT Operations"},"sourceSpaces":null,"history":false,"peopleSource":{"kind":"token","site":"example.atlassian.net","email":"alex@example.com","people":12,"withEmail":10},"connection":null,"files":[],"options":{},"throttledUntil":null,"waitingFor":null,"tokenDeletedAt":null,"counts":{"pages":120,"blogPosts":6,"attachments":40,"attachmentVersions":52,"comments":85,"people":12,"problems":7},"errorCode":null,"quarantineSpace":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0006","key":"ITOPS"},"targetSpace":null,"reimportSpaceId":null,"canManage":true,"canResolve":true,"canTakeOver":false,"startedAt":"2026-10-10T08:00:00.000Z","finishedAt":"2026-10-10T08:05:00.000Z","decidedAt":null,"fileExpiresAt":null,"createdAt":"2026-10-10T07:50:00.000Z","updatedAt":"2026-10-10T08:05:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidSpaceKey`: The space key is not valid. `invalidSpaceName`: The space name is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidSpaceKey":{"value":{"type":"urn:lunedo:problem:invalidSpaceKey","title":"The space key is not valid","status":400,"code":"invalidSpaceKey"}},"invalidSpaceName":{"value":{"type":"urn:lunedo:problem:invalidSpaceName","title":"The space name is not valid","status":400,"code":"invalidSpaceName"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`importNotReady`: The export is still being read. `importStarted`: The import has started. `keyTaken`: The space key is taken. `peopleSourceMissing`: Choose how people are recognized first. `tokenMissing`: The API token of the draft was deleted.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"importNotReady":{"value":{"type":"urn:lunedo:problem:importNotReady","title":"The export is still being read","status":409,"code":"importNotReady"}},"importStarted":{"value":{"type":"urn:lunedo:problem:importStarted","title":"The import has started","status":409,"code":"importStarted"}},"keyTaken":{"value":{"type":"urn:lunedo:problem:keyTaken","title":"The space key is taken","status":409,"code":"keyTaken"}},"peopleSourceMissing":{"value":{"type":"urn:lunedo:problem:peopleSourceMissing","title":"Choose how people are recognized first","status":409,"code":"peopleSourceMissing"}},"tokenMissing":{"value":{"type":"urn:lunedo:problem:tokenMissing","title":"The API token of the draft was deleted","status":409,"code":"tokenMissing"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}},"507":{"description":"`storageFull`: Storage is almost full.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"storageFull":{"value":{"type":"urn:lunedo:problem:storageFull","title":"Storage is almost full","status":507,"code":"storageFull"}}}}}}}}},"/api/v1/imports/{importId}/stop":{"post":{"operationId":"imports.stop","summary":"Stop an import","description":"Stops a running import and deletes the quarantine space with everything imported so far. Confirm with the key of the space. An uploaded file is kept for 7 days.\n\nRequires the permission `import.manage` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.manage","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"confirmation":{"type":"string","maxLength":20,"description":"The key of the space, typed by the person to confirm."}},"required":["confirmation"],"additionalProperties":false,"description":"Confirmation of an action that cannot be undone."},"example":{"confirmation":"ITOPS"}}}},"responses":{"200":{"description":"The import.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the import."},"organizationId":{"type":"string","format":"uuid","description":"Organization the import belongs to."},"importer":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"The administrator who imports."},"source":{"type":"string","description":"What is imported: `confluence-xml` for the XML space export of Confluence Cloud or Data Center, `confluence-csv` for the CSV space export of Confluence Cloud, `confluence-cloud` and `confluence-dc` to read a space through the Confluence API, `markdown` for a ZIP file of Markdown files, `word` for Word documents (`.docx`). New values can be added in later versions; handle unknown values.","x-extensible-enum":["confluence-xml","confluence-csv","confluence-cloud","confluence-dc","markdown","word"]},"state":{"type":"string","description":"State of the import. `draft` while the wizard is filled in, `analyzing` while the export is read, `ready` when it can be started, `running` while it imports, `held` when the importing administrator lost the permission and another administrator has to take over, `stopping` and `discarding` while the quarantine space is deleted, `review` when the quarantine space waits for a decision, `accepted`, `discarded`, `stopped` and `failed` at the end. A re-import is in `running` while it compares or applies, in `review` while changes wait for a decision, `accepted` when everything is applied, and `superseded` when a newer re-import of the same space replaced it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["draft","analyzing","ready","running","held","stopping","review","accepting","accepted","discarding","discarded","stopped","failed","superseded"]},"draftStep":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Step of the wizard the importer was on, for continuing a draft."},"file":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Where the export comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload","folder"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes, or null when not known yet."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload, or null for a file in the import folder."},"complete":{"type":"boolean","description":"Whether the file is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},{"type":"null"}],"description":"The export file, or null when none is chosen yet."},"spaceName":{"description":"Name of the new space.","type":["string","null"]},"spaceKey":{"description":"Key of the new space.","type":["string","null"]},"archived":{"type":"boolean","description":"Whether the space becomes archived when the import is accepted."},"history":{"type":"boolean","description":"Whether every Confluence version becomes a Lunedo version, or only the current state is imported."},"peopleSource":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"How people are recognized: `token` reads names and e-mail addresses with a read-only Atlassian API token, `list` uses a user list exported from the Atlassian administration, `skip` keeps every author as a placeholder, `source` takes the names Confluence Data Center returns through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["token","list","skip","source"]},"site":{"description":"Confluence site the token is used with, or null.","type":["string","null"]},"email":{"description":"Atlassian e-mail address the token belongs to, or null.","type":["string","null"]},"people":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"People of the export the token could read, or people in the user list; null when unknown."},"withEmail":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Of these, people with a visible e-mail address."}},"required":["kind","site","email","people","withEmail"],"additionalProperties":false},{"type":"null"}],"description":"How people are recognized. The token itself is never returned."},"connection":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Kind of Confluence the import reads through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["cloud","dataCenter"]},"site":{"type":"string","description":"Host name of the Confluence site, with the port when it is not 443."},"basePath":{"type":"string","description":"Context path of Confluence Data Center, such as `/confluence`, or empty."},"email":{"description":"Atlassian e-mail address the API token belongs to, or null.","type":["string","null"]},"account":{"description":"Name of the Confluence account the token belongs to.","type":["string","null"]},"selection":{"type":"array","items":{"type":"object","properties":{"importId":{"type":"string","format":"uuid","description":"ID of the import that reads the space."},"spaceKey":{"type":"string","description":"Key of the Confluence space."}},"required":["importId","spaceKey"],"additionalProperties":false},"description":"Spaces chosen with this connection whose imports are not started yet, one import per space, this import included. Empty once the import has started."}},"required":["kind","site","basePath","email","account","selection"],"additionalProperties":false},{"type":"null"}],"description":"The connection of an import through the Confluence API, or null. Several imports of the same importer can share one connection; the token is never returned."},"files":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","description":"Where the document comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload."},"complete":{"type":"boolean","description":"Whether the upload is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},"description":"The Word documents of a `word` import, in their order. Empty for other imports."},"options":{"type":"object","properties":{"spaceKey":{"description":"Key of the Confluence space read through the API or from a site backup.","type":"string"},"pageIds":{"description":"IDs of the top-level pages whose trees are imported; all pages when left out.","type":"array","items":{"type":"string"}},"blogPosts":{"description":"Whether blog posts are imported; true when left out.","type":"boolean"},"split":{"type":"string","description":"`file` makes each Word document one page, `heading` adds a subpage per top-level heading. New values can be added in later versions; handle unknown values.","x-extensible-enum":["file","heading"]},"knowledgeBase":{"description":"For a `markdown` import: whether the new space is a knowledge base.","type":"boolean"}},"additionalProperties":false,"description":"Options of the source."},"throttledUntil":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Until when Confluence asked Lunedo to slow down, or null. The import continues by itself. ISO 8601 timestamp in UTC."},"waitingFor":{"description":"Key of the Confluence space whose import over the same connection reads or runs first, or null. Imports sharing a connection run one after another; this one continues by itself.","type":["string","null"]},"tokenDeletedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the API token was deleted: when the import was accepted, discarded, stopped or failed, when the importer lost the permission to import, or when the draft was left alone for a week. ISO 8601 timestamp in UTC."},"sourceUrl":{"description":"Address of the Confluence site. Links to pages outside the export point there.","type":["string","null"]},"reviewers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"People who can read the quarantine space and the report."},"phase":{"anyOf":[{"type":"string","x-extensible-enum":["read","compare","space","people","pages","attachments","templates","content","comments","reactions","permissions","baseline","finish","lineage","moves","labels","deletions","done"]},{"type":"null"}],"description":"Step the import is in: `read` reads the export, then `space`, `people`, `pages`, `attachments`, `templates`, `content`, `comments`, `reactions`, `permissions`, `baseline` and `finish`; `done` after the last step. A re-import compares in `compare` and applies in `lineage`, `people`, `pages`, `moves`, `attachments`, `templates`, `content`, `labels`, `comments`, `reactions`, `deletions`, `baseline` and `finish`. New values can be added in later versions; handle unknown values."},"progress":{"type":"object","properties":{"done":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units done in the current step."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units of the current step, or 0 when not known."}},"required":["done","total"],"additionalProperties":false,"description":"Progress of the current step."},"found":{"anyOf":[{"type":"object","properties":{"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages in the export."},"blogPosts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Blog posts in the export."},"versions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Earlier versions of pages and blog posts."},"comments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Comments, including inline comments and replies."},"likes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Likes on pages, blog posts and comments."},"watchers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Watchers of pages and the space. They are counted, not imported."},"attachments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Attachments of these pages."},"attachmentBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the current attachment versions in bytes."},"people":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"People named in the export."},"macroKinds":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Different macros used on the pages."},"spaceKey":{"type":"string","description":"Key of the space in Confluence."},"spaceName":{"type":"string","description":"Name of the space in Confluence."}},"required":["pages","blogPosts","versions","comments","likes","watchers","attachments","attachmentBytes","people","macroKinds","spaceKey","spaceName"],"additionalProperties":false},{"type":"null"}],"description":"What the export contains, once it was read."},"sourceSpaces":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the space in Confluence."},"name":{"type":"string","description":"Name of the space in Confluence."}},"required":["key","name"],"additionalProperties":false}},{"type":"null"}],"description":"The spaces of a site backup, once it was read; choose one with `options.spaceKey`. Null for exports and backups of one space."},"counts":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"What was imported, by kind: `pages`, `blogPosts`, `versions`, `attachments`, `attachmentVersions`, `comments`, `inlineAnchored`, `inlineMoved`, `likes`, `watchers`, `people`, `peopleMatched`, `restrictions`, `groupsMissing` and `problems`."},"errorCode":{"description":"Why the export could not be read or the import failed, such as `notAnArchive`, `wrongFormat`, `archiveTooLarge`, `unsafeEntryName`, `xmlDeclaration`, `spaceChoiceRequired` (a site backup with several spaces; see `sourceSpaces`) or `internalError`.","type":["string","null"]},"quarantineSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."}},"required":["id","key"],"additionalProperties":false},{"type":"null"}],"description":"The space the import writes into."},"targetSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"name":{"type":"string","description":"Name of the space."}},"required":["id","key","name"],"additionalProperties":false},{"type":"null"}],"description":"For a re-import, the space created by the earlier import that the changes go into; otherwise null."},"reimportSpaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space a newer export of the same Confluence space can be imported into again, or null when this import offers no re-import."},"canManage":{"type":"boolean","description":"Whether the caller can change, start, stop, accept or discard the import."},"canResolve":{"type":"boolean","description":"Whether the caller can map people and groups of the import or apply a user list."},"canTakeOver":{"type":"boolean","description":"Whether the caller can take over a held import."},"startedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import finished or failed. ISO 8601 timestamp in UTC."},"decidedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import was accepted, discarded or stopped. ISO 8601 timestamp in UTC."},"fileExpiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When an uploaded file is deleted. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the import was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the import last changed. ISO 8601 timestamp in UTC."}},"required":["id","organizationId","importer","source","state","draftStep","file","spaceName","spaceKey","archived","history","peopleSource","connection","files","options","throttledUntil","waitingFor","tokenDeletedAt","sourceUrl","reviewers","phase","progress","found","sourceSpaces","counts","errorCode","quarantineSpace","targetSpace","reimportSpaceId","canManage","canResolve","canTakeOver","startedAt","finishedAt","decidedAt","fileExpiresAt","createdAt","updatedAt"],"additionalProperties":false,"description":"An import of a Confluence space."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0001","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0002","importer":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0003","name":"Alex Admin"},"source":"confluence-xml","state":"stopping","draftStep":3,"file":{"kind":"upload","name":"export.zip","size":1048576,"uploadId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0004","complete":true},"spaceName":"IT Operations","spaceKey":"ITOPS","archived":false,"sourceUrl":"https://example.atlassian.net/wiki","reviewers":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0005","name":"Robin Reviewer"}],"phase":null,"progress":{"done":0,"total":0},"found":{"pages":120,"blogPosts":6,"versions":340,"comments":85,"likes":30,"watchers":44,"attachments":40,"attachmentBytes":2048000,"people":12,"macroKinds":6,"spaceKey":"ITOPS","spaceName":"IT Operations"},"sourceSpaces":null,"history":false,"peopleSource":{"kind":"token","site":"example.atlassian.net","email":"alex@example.com","people":12,"withEmail":10},"connection":null,"files":[],"options":{},"throttledUntil":null,"waitingFor":null,"tokenDeletedAt":null,"counts":{"pages":120,"blogPosts":6,"attachments":40,"attachmentVersions":52,"comments":85,"people":12,"problems":7},"errorCode":null,"quarantineSpace":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0006","key":"ITOPS"},"targetSpace":null,"reimportSpaceId":null,"canManage":true,"canResolve":true,"canTakeOver":false,"startedAt":"2026-10-10T08:00:00.000Z","finishedAt":"2026-10-10T08:05:00.000Z","decidedAt":null,"fileExpiresAt":null,"createdAt":"2026-10-10T07:50:00.000Z","updatedAt":"2026-10-10T08:05:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `confirmationMismatch`: The confirmation does not match. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"confirmationMismatch":{"value":{"type":"urn:lunedo:problem:confirmationMismatch","title":"The confirmation does not match","status":400,"code":"confirmationMismatch"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`importNotRunning`: The import is not running.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"importNotRunning":{"value":{"type":"urn:lunedo:problem:importNotRunning","title":"The import is not running","status":409,"code":"importNotRunning"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/imports/{importId}/take-over":{"post":{"operationId":"imports.takeOver","summary":"Take over an import","description":"Continues an import whose importing administrator lost the permission to import. The caller becomes the importing administrator. The change is audited.\n\nRequires the permission `import.takeOver` on the import in `importId`.","tags":["Imports"],"x-lunedo-permission":{"action":"import.takeOver","resource":"import","parameter":"importId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The import.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the import."},"organizationId":{"type":"string","format":"uuid","description":"Organization the import belongs to."},"importer":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"The administrator who imports."},"source":{"type":"string","description":"What is imported: `confluence-xml` for the XML space export of Confluence Cloud or Data Center, `confluence-csv` for the CSV space export of Confluence Cloud, `confluence-cloud` and `confluence-dc` to read a space through the Confluence API, `markdown` for a ZIP file of Markdown files, `word` for Word documents (`.docx`). New values can be added in later versions; handle unknown values.","x-extensible-enum":["confluence-xml","confluence-csv","confluence-cloud","confluence-dc","markdown","word"]},"state":{"type":"string","description":"State of the import. `draft` while the wizard is filled in, `analyzing` while the export is read, `ready` when it can be started, `running` while it imports, `held` when the importing administrator lost the permission and another administrator has to take over, `stopping` and `discarding` while the quarantine space is deleted, `review` when the quarantine space waits for a decision, `accepted`, `discarded`, `stopped` and `failed` at the end. A re-import is in `running` while it compares or applies, in `review` while changes wait for a decision, `accepted` when everything is applied, and `superseded` when a newer re-import of the same space replaced it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["draft","analyzing","ready","running","held","stopping","review","accepting","accepted","discarding","discarded","stopped","failed","superseded"]},"draftStep":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Step of the wizard the importer was on, for continuing a draft."},"file":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Where the export comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload","folder"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes, or null when not known yet."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload, or null for a file in the import folder."},"complete":{"type":"boolean","description":"Whether the file is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},{"type":"null"}],"description":"The export file, or null when none is chosen yet."},"spaceName":{"description":"Name of the new space.","type":["string","null"]},"spaceKey":{"description":"Key of the new space.","type":["string","null"]},"archived":{"type":"boolean","description":"Whether the space becomes archived when the import is accepted."},"history":{"type":"boolean","description":"Whether every Confluence version becomes a Lunedo version, or only the current state is imported."},"peopleSource":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"How people are recognized: `token` reads names and e-mail addresses with a read-only Atlassian API token, `list` uses a user list exported from the Atlassian administration, `skip` keeps every author as a placeholder, `source` takes the names Confluence Data Center returns through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["token","list","skip","source"]},"site":{"description":"Confluence site the token is used with, or null.","type":["string","null"]},"email":{"description":"Atlassian e-mail address the token belongs to, or null.","type":["string","null"]},"people":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"People of the export the token could read, or people in the user list; null when unknown."},"withEmail":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Of these, people with a visible e-mail address."}},"required":["kind","site","email","people","withEmail"],"additionalProperties":false},{"type":"null"}],"description":"How people are recognized. The token itself is never returned."},"connection":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Kind of Confluence the import reads through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["cloud","dataCenter"]},"site":{"type":"string","description":"Host name of the Confluence site, with the port when it is not 443."},"basePath":{"type":"string","description":"Context path of Confluence Data Center, such as `/confluence`, or empty."},"email":{"description":"Atlassian e-mail address the API token belongs to, or null.","type":["string","null"]},"account":{"description":"Name of the Confluence account the token belongs to.","type":["string","null"]},"selection":{"type":"array","items":{"type":"object","properties":{"importId":{"type":"string","format":"uuid","description":"ID of the import that reads the space."},"spaceKey":{"type":"string","description":"Key of the Confluence space."}},"required":["importId","spaceKey"],"additionalProperties":false},"description":"Spaces chosen with this connection whose imports are not started yet, one import per space, this import included. Empty once the import has started."}},"required":["kind","site","basePath","email","account","selection"],"additionalProperties":false},{"type":"null"}],"description":"The connection of an import through the Confluence API, or null. Several imports of the same importer can share one connection; the token is never returned."},"files":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","description":"Where the document comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload."},"complete":{"type":"boolean","description":"Whether the upload is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},"description":"The Word documents of a `word` import, in their order. Empty for other imports."},"options":{"type":"object","properties":{"spaceKey":{"description":"Key of the Confluence space read through the API or from a site backup.","type":"string"},"pageIds":{"description":"IDs of the top-level pages whose trees are imported; all pages when left out.","type":"array","items":{"type":"string"}},"blogPosts":{"description":"Whether blog posts are imported; true when left out.","type":"boolean"},"split":{"type":"string","description":"`file` makes each Word document one page, `heading` adds a subpage per top-level heading. New values can be added in later versions; handle unknown values.","x-extensible-enum":["file","heading"]},"knowledgeBase":{"description":"For a `markdown` import: whether the new space is a knowledge base.","type":"boolean"}},"additionalProperties":false,"description":"Options of the source."},"throttledUntil":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Until when Confluence asked Lunedo to slow down, or null. The import continues by itself. ISO 8601 timestamp in UTC."},"waitingFor":{"description":"Key of the Confluence space whose import over the same connection reads or runs first, or null. Imports sharing a connection run one after another; this one continues by itself.","type":["string","null"]},"tokenDeletedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the API token was deleted: when the import was accepted, discarded, stopped or failed, when the importer lost the permission to import, or when the draft was left alone for a week. ISO 8601 timestamp in UTC."},"sourceUrl":{"description":"Address of the Confluence site. Links to pages outside the export point there.","type":["string","null"]},"reviewers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"People who can read the quarantine space and the report."},"phase":{"anyOf":[{"type":"string","x-extensible-enum":["read","compare","space","people","pages","attachments","templates","content","comments","reactions","permissions","baseline","finish","lineage","moves","labels","deletions","done"]},{"type":"null"}],"description":"Step the import is in: `read` reads the export, then `space`, `people`, `pages`, `attachments`, `templates`, `content`, `comments`, `reactions`, `permissions`, `baseline` and `finish`; `done` after the last step. A re-import compares in `compare` and applies in `lineage`, `people`, `pages`, `moves`, `attachments`, `templates`, `content`, `labels`, `comments`, `reactions`, `deletions`, `baseline` and `finish`. New values can be added in later versions; handle unknown values."},"progress":{"type":"object","properties":{"done":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units done in the current step."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units of the current step, or 0 when not known."}},"required":["done","total"],"additionalProperties":false,"description":"Progress of the current step."},"found":{"anyOf":[{"type":"object","properties":{"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages in the export."},"blogPosts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Blog posts in the export."},"versions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Earlier versions of pages and blog posts."},"comments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Comments, including inline comments and replies."},"likes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Likes on pages, blog posts and comments."},"watchers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Watchers of pages and the space. They are counted, not imported."},"attachments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Attachments of these pages."},"attachmentBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the current attachment versions in bytes."},"people":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"People named in the export."},"macroKinds":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Different macros used on the pages."},"spaceKey":{"type":"string","description":"Key of the space in Confluence."},"spaceName":{"type":"string","description":"Name of the space in Confluence."}},"required":["pages","blogPosts","versions","comments","likes","watchers","attachments","attachmentBytes","people","macroKinds","spaceKey","spaceName"],"additionalProperties":false},{"type":"null"}],"description":"What the export contains, once it was read."},"sourceSpaces":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the space in Confluence."},"name":{"type":"string","description":"Name of the space in Confluence."}},"required":["key","name"],"additionalProperties":false}},{"type":"null"}],"description":"The spaces of a site backup, once it was read; choose one with `options.spaceKey`. Null for exports and backups of one space."},"counts":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"What was imported, by kind: `pages`, `blogPosts`, `versions`, `attachments`, `attachmentVersions`, `comments`, `inlineAnchored`, `inlineMoved`, `likes`, `watchers`, `people`, `peopleMatched`, `restrictions`, `groupsMissing` and `problems`."},"errorCode":{"description":"Why the export could not be read or the import failed, such as `notAnArchive`, `wrongFormat`, `archiveTooLarge`, `unsafeEntryName`, `xmlDeclaration`, `spaceChoiceRequired` (a site backup with several spaces; see `sourceSpaces`) or `internalError`.","type":["string","null"]},"quarantineSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."}},"required":["id","key"],"additionalProperties":false},{"type":"null"}],"description":"The space the import writes into."},"targetSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"name":{"type":"string","description":"Name of the space."}},"required":["id","key","name"],"additionalProperties":false},{"type":"null"}],"description":"For a re-import, the space created by the earlier import that the changes go into; otherwise null."},"reimportSpaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space a newer export of the same Confluence space can be imported into again, or null when this import offers no re-import."},"canManage":{"type":"boolean","description":"Whether the caller can change, start, stop, accept or discard the import."},"canResolve":{"type":"boolean","description":"Whether the caller can map people and groups of the import or apply a user list."},"canTakeOver":{"type":"boolean","description":"Whether the caller can take over a held import."},"startedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import finished or failed. ISO 8601 timestamp in UTC."},"decidedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import was accepted, discarded or stopped. ISO 8601 timestamp in UTC."},"fileExpiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When an uploaded file is deleted. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the import was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the import last changed. ISO 8601 timestamp in UTC."}},"required":["id","organizationId","importer","source","state","draftStep","file","spaceName","spaceKey","archived","history","peopleSource","connection","files","options","throttledUntil","waitingFor","tokenDeletedAt","sourceUrl","reviewers","phase","progress","found","sourceSpaces","counts","errorCode","quarantineSpace","targetSpace","reimportSpaceId","canManage","canResolve","canTakeOver","startedAt","finishedAt","decidedAt","fileExpiresAt","createdAt","updatedAt"],"additionalProperties":false,"description":"An import of a Confluence space."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0001","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0002","importer":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0003","name":"Alex Admin"},"source":"confluence-xml","state":"running","draftStep":3,"file":{"kind":"upload","name":"export.zip","size":1048576,"uploadId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0004","complete":true},"spaceName":"IT Operations","spaceKey":"ITOPS","archived":false,"sourceUrl":"https://example.atlassian.net/wiki","reviewers":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0005","name":"Robin Reviewer"}],"phase":null,"progress":{"done":0,"total":0},"found":{"pages":120,"blogPosts":6,"versions":340,"comments":85,"likes":30,"watchers":44,"attachments":40,"attachmentBytes":2048000,"people":12,"macroKinds":6,"spaceKey":"ITOPS","spaceName":"IT Operations"},"sourceSpaces":null,"history":false,"peopleSource":{"kind":"token","site":"example.atlassian.net","email":"alex@example.com","people":12,"withEmail":10},"connection":null,"files":[],"options":{},"throttledUntil":null,"waitingFor":null,"tokenDeletedAt":null,"counts":{"pages":120,"blogPosts":6,"attachments":40,"attachmentVersions":52,"comments":85,"people":12,"problems":7},"errorCode":null,"quarantineSpace":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0006","key":"ITOPS"},"targetSpace":null,"reimportSpaceId":null,"canManage":true,"canResolve":true,"canTakeOver":false,"startedAt":"2026-10-10T08:00:00.000Z","finishedAt":"2026-10-10T08:05:00.000Z","decidedAt":null,"fileExpiresAt":null,"createdAt":"2026-10-10T07:50:00.000Z","updatedAt":"2026-10-10T08:05:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`importNotHeld`: The import is not waiting for an administrator.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"importNotHeld":{"value":{"type":"urn:lunedo:problem:importNotHeld","title":"The import is not waiting for an administrator","status":409,"code":"importNotHeld"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/accounts":{"get":{"operationId":"instance.accounts","summary":"List all accounts","description":"Lists every account of the instance, including service accounts, with instance roles, second-factor state and last sign-in. `q` searches name and e-mail address.\n\nRequires the permission `instance.accounts.view` on the instance.","tags":["Instance"],"x-lunedo-permission":{"action":"instance.accounts.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}},{"name":"q","in":"query","required":false,"description":"Only items that contain this text, ignoring case: in the name and e-mail address of accounts and members, the name and short name of organizations, and the name and description of groups.","schema":{"type":"string","maxLength":200}},{"name":"withoutOrganization","in":"query","required":false,"description":"With true, only accounts without any current membership in an organization.","schema":{"type":"string","enum":["true","false"]}},{"name":"state","in":"query","required":false,"description":"Only accounts in this lifecycle state.","schema":{"type":"string","enum":["active","deactivated","anonymized","placeholder"]}}],"responses":{"200":{"description":"Accounts of the instance.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"type":{"type":"string","enum":["standard","guest","portal","service"],"description":"Kind of account."},"state":{"type":"string","enum":["invited","active","deactivated","anonymized","placeholder"],"description":"Lifecycle state of the account."},"email":{"description":"E-mail address, or null.","type":["string","null"]},"name":{"type":"string","description":"Display name."},"homeOrganizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization the account belongs to, or null."},"createdAt":{"type":"string","format":"date-time","description":"When the account was created. ISO 8601 timestamp in UTC."},"lastSignInAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the account signed in last, or null. ISO 8601 timestamp in UTC."},"twoFactorActive":{"type":"boolean","description":"Whether the account has an authenticator app or a passkey."},"secondFactorRequired":{"type":"boolean","description":"Whether the instance or the home organization requires a second factor that the account does not have yet."},"managedBy":{"anyOf":[{"type":"object","properties":{"providerId":{"type":"string","format":"uuid","description":"ID of the identity provider."},"providerName":{"type":"string","description":"Name of the identity provider."},"providerType":{"type":"string","description":"Kind of identity provider. New values can be added in later versions; handle unknown values.","x-extensible-enum":["oidc","saml","ldap"]},"source":{"type":"string","enum":["identity","domain"],"description":"Why the provider manages the account: `identity` when an identity of the provider is linked, `domain` when the e-mail domain of the account is assigned to the provider."},"since":{"type":"string","format":"date-time","description":"Since when the provider manages the account. ISO 8601 timestamp in UTC."}},"required":["providerId","providerName","providerType","source","since"],"additionalProperties":false},{"type":"null"}],"description":"The identity provider that manages the account, or null for a local account. Accounts managed by an OpenID Connect or SAML provider sign in only through it and have no password, passkey or authenticator app in Lunedo; accounts managed by a directory sign in with its password and keep their second factor in Lunedo."},"instanceRoles":{"type":"array","items":{"type":"object","properties":{"builtInRole":{"anyOf":[{"type":"string","enum":["owner","administrator","member","securityAuditor"]},{"type":"null"}],"description":"Key of the built-in role, or null for a custom role."},"customRoleId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the custom instance role, or null."},"name":{"description":"Name of the custom role, or null for a built-in role.","type":["string","null"]}},"required":["builtInRole","customRoleId","name"],"additionalProperties":false,"description":"An instance role the account holds."},"description":"Instance roles of the account, the instance owner first."},"organizations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the organization."},"name":{"type":"string","description":"Name of the organization."},"home":{"type":"boolean","description":"Whether this is the home organization of the account."}},"required":["id","name","home"],"additionalProperties":false,"description":"An organization the account is a member, collaborator or guest of."},"description":"Current memberships of the account, the home organization first."}},"required":["id","type","state","email","name","homeOrganizationId","createdAt","lastSignInAt","twoFactorActive","secondFactorRequired","managedBy","instanceRoles","organizations"],"additionalProperties":false,"description":"An account of the instance with what administrators need to see."},"description":"Accounts, ordered by name."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"One page of results."},"example":{"items":[{"id":"01929b1e-8d4b-7e3f-a05c-4d3e2f1a6b7c","type":"standard","state":"active","email":"ada@example.org","name":"Ada Lovelace","homeOrganizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","createdAt":"2026-10-01T08:00:00.000Z","lastSignInAt":"2026-10-01T09:30:00.000Z","twoFactorActive":true,"secondFactorRequired":false,"managedBy":{"providerId":"01929b1f-1b7e-7b62-938f-7a6b5c4d9e0f","providerName":"Company login","providerType":"oidc","source":"identity","since":"2026-09-14T07:45:00.000Z"},"instanceRoles":[{"builtInRole":"securityAuditor","customRoleId":null,"name":null}],"organizations":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","name":"Example Inc.","home":true}]}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/instance/accounts/{accountId}/anonymize":{"post":{"operationId":"instance.anonymize","summary":"Anonymize an account","description":"Removes the name, e-mail address, sign-in names and profile of the account for good, and deletes its identities, sessions, tokens, passkeys, second factors and personal settings. Its memberships end. The account stays as a former user with its ID; content keeps this pseudonym, and the audit log can no longer show its personal data. Copies of the audit log exported or streamed before are outside Lunedo. Needs a signed-in session with a recent confirmation of identity.\n\nRequires the permission `instance.accounts.manage` on the instance. Needs a signed-in session; API tokens are refused.","tags":["Instance"],"x-lunedo-permission":{"action":"instance.accounts.manage","resource":"instance"},"security":[{"sessionCookie":[]}],"parameters":[{"name":"accountId","in":"path","required":true,"description":"ID of the account.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":500,"description":"Why the account is anonymized, 1 to 500 characters. Kept in the audit log; do not name the person."},"confirmation":{"type":"string","maxLength":200,"description":"The current name of the account, typed to confirm."}},"required":["reason","confirmation"],"additionalProperties":false,"description":"Confirmation of the anonymization."},"example":{"reason":"Erasure request of 1 October 2026","confirmation":"Erika Example"}}}},"responses":{"200":{"description":"What was removed.","content":{"application/json":{"schema":{"type":"object","properties":{"endedSessions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Sessions that ended."},"removedIdentities":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Linked identities that were removed."},"endedMemberships":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Memberships that ended."}},"required":["endedSessions","removedIdentities","endedMemberships"],"additionalProperties":false,"description":"What the anonymization removed."},"example":{"endedSessions":1,"removedIdentities":1,"endedMemberships":2}}}},"400":{"description":"`anonymizeSelf`: An account cannot anonymize itself. `confirmationMismatch`: The confirmation does not match. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"anonymizeSelf":{"value":{"type":"urn:lunedo:problem:anonymizeSelf","title":"An account cannot anonymize itself","status":400,"code":"anonymizeSelf"}},"confirmationMismatch":{"value":{"type":"urn:lunedo:problem:confirmationMismatch","title":"The confirmation does not match","status":400,"code":"confirmationMismatch"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `reauthenticationRequired`: Confirm your identity first. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"reauthenticationRequired":{"value":{"type":"urn:lunedo:problem:reauthenticationRequired","title":"Confirm your identity first","status":403,"code":"reauthenticationRequired"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`instanceOwner`: The instance owner cannot be changed this way. `lastOwner`: The last owner cannot leave.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"instanceOwner":{"value":{"type":"urn:lunedo:problem:instanceOwner","title":"The instance owner cannot be changed this way","status":409,"code":"instanceOwner"}},"lastOwner":{"value":{"type":"urn:lunedo:problem:lastOwner","title":"The last owner cannot leave","status":409,"code":"lastOwner"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/accounts/{accountId}/merge":{"post":{"operationId":"instance.mergePlaceholder","summary":"Merge a placeholder into an account","description":"Moves the memberships, group memberships and organization roles of the placeholder to the account. The placeholder keeps its ID and points to the account. Nobody can merge a placeholder into their own account. Needs a recent confirmation of identity.\n\nRequires the permission `instance.accounts.manage` on the instance. Needs a signed-in session; API tokens are refused.","tags":["Instance"],"x-lunedo-permission":{"action":"instance.accounts.manage","resource":"instance"},"security":[{"sessionCookie":[]}],"parameters":[{"name":"accountId","in":"path","required":true,"description":"ID of the placeholder.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the account that takes over the placeholder."}},"required":["accountId"],"additionalProperties":false,"description":"The account to merge the placeholder into."},"example":{"accountId":"01929b1e-8d4b-7e3f-a05c-4d3e2f1a6b7c"}}}},"responses":{"200":{"description":"What moved.","content":{"application/json":{"schema":{"type":"object","properties":{"memberships":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Memberships the placeholder had."},"groups":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Group memberships the placeholder had."},"roles":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Role assignments the placeholder had."}},"required":["memberships","groups","roles"],"additionalProperties":false,"description":"What moved from the placeholder to the account."},"example":{"memberships":1,"groups":2,"roles":0}}}},"400":{"description":"`invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `reauthenticationRequired`: Confirm your identity first. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"reauthenticationRequired":{"value":{"type":"urn:lunedo:problem:reauthenticationRequired","title":"Confirm your identity first","status":403,"code":"reauthenticationRequired"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notPlaceholder`: The account is not a placeholder that can be merged.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notPlaceholder":{"value":{"type":"urn:lunedo:problem:notPlaceholder","title":"The account is not a placeholder that can be merged","status":409,"code":"notPlaceholder"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/accounts/{accountId}/organization":{"post":{"operationId":"instance.assignOrganization","summary":"Assign an organization to an account without one","description":"Makes the organization the home organization of the account and adds the account as a member. Only for accounts that have no organization yet.\n\nRequires the permission `instance.accounts.manage` on the instance.","tags":["Instance"],"x-lunedo-permission":{"action":"instance.accounts.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"accountId","in":"path","required":true,"description":"ID of the account.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"organizationId":{"type":"string","format":"uuid","description":"ID of the organization the account belongs to from now on."}},"required":["organizationId"],"additionalProperties":false,"description":"The organization to assign."},"example":{"organizationId":"01929b1f-0a6d-7a51-827e-6f5a4b3c8d9e"}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `guestMembership`: Guest and portal accounts can only be guests. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"guestMembership":{"value":{"type":"urn:lunedo:problem:guestMembership","title":"Guest and portal accounts can only be guests","status":400,"code":"guestMembership"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`accountHasOrganization`: The account belongs to an organization already.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"accountHasOrganization":{"value":{"type":"urn:lunedo:problem:accountHasOrganization","title":"The account belongs to an organization already","status":409,"code":"accountHasOrganization"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/accounts/placeholders":{"post":{"operationId":"instance.createPlaceholder","summary":"Create a placeholder","description":"Creates an account for a person who has not signed in yet, for example the author of imported content. When the person signs in through a provider with this e-mail address and the provider verifies it, the placeholder becomes their account; otherwise an administrator merges it.\n\nRequires the permission `instance.accounts.manage` on the instance.","tags":["Instance"],"x-lunedo-permission":{"action":"instance.accounts.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"Name of the person, as content will show it."},"email":{"type":"string","maxLength":254,"format":"email","description":"E-mail address of the person. A verified sign-in with this address turns the placeholder into the account."}},"required":["name","email"],"additionalProperties":false,"description":"A person who has no account yet."},"example":{"name":"Erika Example","email":"erika@example.com"}}}},"responses":{"201":{"description":"The placeholder.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the placeholder."},"name":{"type":"string","description":"Name."},"email":{"type":"string","description":"E-mail address."}},"required":["id","name","email"],"additionalProperties":false,"description":"A placeholder."},"example":{"id":"01929b1f-0a6d-7a51-827e-6f5a4b3c8d9f","name":"Erika Example","email":"erika@example.com"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"409":{"description":"`emailInUse`: The e-mail address is in use.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"emailInUse":{"value":{"type":"urn:lunedo:problem:emailInUse","title":"The e-mail address is in use","status":409,"code":"emailInUse"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/announcement":{"delete":{"operationId":"announcements.removeInstance","summary":"Remove the instance announcement","description":"Removes the banner of the instance for everyone at once.\n\nRequires the permission `instance.settings.manage` on the instance.","tags":["Announcements"],"x-lunedo-permission":{"action":"instance.settings.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"get":{"operationId":"announcements.instance","summary":"Get the instance announcement","description":"Returns the banner of the instance as set, also when it has ended or starts later.\n\nRequires the permission `instance.settings.view` on the instance.","tags":["Announcements"],"x-lunedo-permission":{"action":"instance.settings.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"200":{"description":"The announcement.","content":{"application/json":{"schema":{"type":"object","properties":{"announcement":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the announcement. It stays the same when the announcement is changed."},"scope":{"type":"string","enum":["instance","organization"],"description":"Who set it."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The organization, or null for the instance."},"version":{"type":"string","format":"uuid","description":"Changes with every change of the announcement."},"severity":{"type":"string","enum":["information","warning"],"description":"`information` can be dismissed by each person until the announcement changes; `warning` stays until its end."},"text":{"type":"string","description":"The text."},"link":{"anyOf":[{"type":"object","properties":{"url":{"type":"string","maxLength":2000,"description":"Address starting with https:// or http://."},"label":{"type":"string","maxLength":60,"description":"Text of the link."}},"required":["url","label"],"additionalProperties":false,"description":"A link shown after the text."},{"type":"null"}],"description":"The link, or null."},"startsAt":{"type":"string","format":"date-time","description":"When it starts to show. ISO 8601 timestamp in UTC."},"endsAt":{"type":"string","format":"date-time","description":"When it stops showing. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When it was last changed. ISO 8601 timestamp in UTC."},"updatedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the person."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who changed it last."}},"required":["id","scope","organizationId","version","severity","text","link","startsAt","endsAt","updatedAt","updatedBy"],"additionalProperties":false,"description":"An announcement banner."},{"type":"null"}],"description":"The announcement, or null when none is set."}},"required":["announcement"],"additionalProperties":false,"description":"The current announcement."},"example":{"announcement":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","scope":"organization","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a01","version":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a41","severity":"information","text":"New: search in attachments. PDF, Word and Excel files are now searchable.","link":{"url":"https://wiki.example.org/spaces/ENG/blog","label":"Read the post"},"startsAt":"2026-10-14T08:00:00.000Z","endsAt":"2026-10-21T08:00:00.000Z","updatedAt":"2026-10-14T07:55:00.000Z","updatedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Weber"}}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"put":{"operationId":"announcements.setInstance","summary":"Set the instance announcement","description":"Shows a banner on every screen of signed-in people, above an organization's banner. Open sessions show the change at once.\n\nRequires the permission `instance.settings.manage` on the instance.","tags":["Announcements"],"x-lunedo-permission":{"action":"instance.settings.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"severity":{"type":"string","enum":["information","warning"],"description":"`information` can be dismissed by each person until the announcement changes; `warning` stays until its end."},"text":{"type":"string","maxLength":300,"description":"Up to 300 characters."},"link":{"default":null,"description":"A link shown after the text, or null.","anyOf":[{"type":"object","properties":{"url":{"type":"string","maxLength":2000,"description":"Address starting with https:// or http://."},"label":{"type":"string","maxLength":60,"description":"Text of the link."}},"required":["url","label"],"additionalProperties":false},{"type":"null"}]},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When it starts to show, or null for now. ISO 8601 timestamp; an offset is allowed."},"endsAt":{"description":"When it stops showing. Needs to be in the future and after the start. ISO 8601 timestamp; an offset is allowed.","type":"string","format":"date-time"}},"required":["severity","text","endsAt"],"additionalProperties":false,"description":"The announcement. It replaces the current one; everyone sees it again, also people who dismissed it."},"example":{"severity":"information","text":"New: search in attachments. PDF, Word and Excel files are now searchable.","link":{"url":"https://wiki.example.org/spaces/ENG/blog","label":"Read the post"},"startsAt":null,"endsAt":"2026-10-21T08:00:00.000Z"}}}},"responses":{"200":{"description":"The announcement.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the announcement. It stays the same when the announcement is changed."},"scope":{"type":"string","enum":["instance","organization"],"description":"Who set it."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The organization, or null for the instance."},"version":{"type":"string","format":"uuid","description":"Changes with every change of the announcement."},"severity":{"type":"string","enum":["information","warning"],"description":"`information` can be dismissed by each person until the announcement changes; `warning` stays until its end."},"text":{"type":"string","description":"The text."},"link":{"anyOf":[{"type":"object","properties":{"url":{"type":"string","maxLength":2000,"description":"Address starting with https:// or http://."},"label":{"type":"string","maxLength":60,"description":"Text of the link."}},"required":["url","label"],"additionalProperties":false,"description":"A link shown after the text."},{"type":"null"}],"description":"The link, or null."},"startsAt":{"type":"string","format":"date-time","description":"When it starts to show. ISO 8601 timestamp in UTC."},"endsAt":{"type":"string","format":"date-time","description":"When it stops showing. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When it was last changed. ISO 8601 timestamp in UTC."},"updatedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the person."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who changed it last."}},"required":["id","scope","organizationId","version","severity","text","link","startsAt","endsAt","updatedAt","updatedBy"],"additionalProperties":false,"description":"An announcement banner."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","scope":"organization","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a01","version":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a41","severity":"information","text":"New: search in attachments. PDF, Word and Excel files are now searchable.","link":{"url":"https://wiki.example.org/spaces/ENG/blog","label":"Read the post"},"startsAt":"2026-10-14T08:00:00.000Z","endsAt":"2026-10-21T08:00:00.000Z","updatedAt":"2026-10-14T07:55:00.000Z","updatedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Weber"}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidAnnouncement`: The announcement is not valid. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidAnnouncement":{"value":{"type":"urn:lunedo:problem:invalidAnnouncement","title":"The announcement is not valid","status":400,"code":"invalidAnnouncement"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/audit-events":{"get":{"operationId":"audit.listInstance","summary":"List audit events of the instance","description":"Lists events of the instance and of all organizations, newest first, with optional filters.\n\nRequires the permission `instance.audit.view` on the instance.","tags":["Audit log"],"x-lunedo-permission":{"action":"instance.audit.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"from","in":"query","required":false,"description":"Only events at or after this time. ISO 8601 timestamp; an offset is allowed.","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"description":"Only events before this time. ISO 8601 timestamp; an offset is allowed.","schema":{"type":"string","format":"date-time"}},{"name":"actorId","in":"query","required":false,"description":"Only events of this account.","schema":{"type":"string","format":"uuid"}},{"name":"personId","in":"query","required":false,"description":"Only events about this person: those they did and those that name them as the target or the account or holder concerned.","schema":{"type":"string","format":"uuid"}},{"name":"targetType","in":"query","required":false,"description":"Only events about this kind of object, for example `group`.","schema":{"type":"string","maxLength":100}},{"name":"targetId","in":"query","required":false,"description":"Only events about this object. Combine it with `targetType`.","schema":{"type":"string","maxLength":200}},{"name":"name","in":"query","required":false,"description":"Only events of this type, for example `role.assigned`.","schema":{"type":"string","maxLength":100}},{"name":"organizationId","in":"query","required":false,"description":"Only events of this organization.","schema":{"type":"string","format":"uuid"}},{"name":"level","in":"query","required":false,"description":"`instance` lists only events of the instance itself, without those of organizations. With `personId` it adds the events about that account in its organizations, such as ended sessions or a reset second factor.","schema":{"type":"string","enum":["instance"]}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"A page of events.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the event."},"scopeType":{"type":"string","enum":["instance","organization"],"description":"Whether the event belongs to the instance or to an organization."},"scopeId":{"type":"string","format":"uuid","description":"ID of the organization, or the instance ID of all zeros."},"sequence":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Position in the tamper-evident chain of the scope."},"name":{"type":"string","description":"Event type, for example `role.assigned`."},"actorType":{"type":"string","description":"`account`, `system` or `anonymous`."},"actorId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Account that acted, or null."},"targetType":{"type":"string","description":"Kind of object the event is about."},"targetId":{"description":"ID of the object, or null.","type":["string","null"]},"fields":{"description":"Event details. Their shape depends on the event type.","$ref":"#/components/schemas/Schema113ae44d8375"},"occurredAt":{"type":"string","format":"date-time","description":"When the event happened. ISO 8601 timestamp in UTC."},"requestId":{"description":"ID of the HTTP request, or null.","type":["string","null"]},"clientIp":{"description":"Client IP address, or null.","type":["string","null"]},"userAgent":{"description":"User agent of the client, or null.","type":["string","null"]},"labelKey":{"type":"string","description":"Translation key of the action, `audit.events.` followed by the event type."},"changeKind":{"type":"string","enum":["setting","fields"],"description":"How `changes` reads: a setting value or lock, or changed fields."},"actor":{"type":"object","properties":{"type":{"type":"string","description":"`account`, `system` or `anonymous`."},"id":{"description":"ID of the account. For `system`, the part of Lunedo that acted: `setupAssistant` for the setup assistant before the owner account exists, or null for other automatic actions. More values may be added. Null for `anonymous`.","type":["string","null"]},"name":{"description":"Name of the account when the event happened, or null.","type":["string","null"]},"former":{"type":"boolean","description":"Whether the account was anonymized; its name and other personal data are gone."},"serviceAccount":{"type":"boolean","description":"Whether the account is a service account."},"token":{"description":"Name of the API token the account acted with, or null when it acted without one.","type":["string","null"]}},"required":["type","id","name","former","serviceAccount","token"],"additionalProperties":false,"description":"Who acted."},"target":{"type":"object","properties":{"type":{"type":"string","description":"Kind of object."},"id":{"description":"ID of the object, or for settings the setting key.","type":["string","null"]},"name":{"description":"Name of the object when the event happened, or null.","type":["string","null"]},"former":{"type":"boolean","description":"Whether the object is an anonymized account; its name and other personal data are gone."}},"required":["type","id","name","former"],"additionalProperties":false,"description":"What the event is about."},"scope":{"type":"object","properties":{"type":{"type":"string","enum":["instance","organization","account"],"description":"Instance, organization, or the account for events about one person's own account."},"id":{"description":"ID of the organization or account, null for the instance.","type":["string","null"]},"name":{"description":"Name of the organization or account when the event happened, or null.","type":["string","null"]}},"required":["type","id","name"],"additionalProperties":false,"description":"Where the event happened."},"changes":{"type":"array","items":{"type":"object","properties":{"property":{"type":"string","description":"Changed property or field."},"old":{"description":"Value before, or null when unknown or not set.","$ref":"#/components/schemas/Schemafbc378f59d82"},"new":{"description":"Value after, or null when removed.","$ref":"#/components/schemas/Schema682d67ac39ef"}},"required":["property","old","new"],"additionalProperties":false,"description":"One change."},"description":"What changed, readable without the raw fields."},"references":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"},"description":"Names of accounts, organizations, groups and roles that the fields refer to, by ID."},"formerAccounts":{"type":"array","items":{"type":"string"},"description":"Anonymized accounts the event refers to, shown as former users with their ID."},"peopleHidden":{"type":"boolean","description":"Whether the people involved are left out because the event concerns a confidential space the reader is not a member of. The actor, referenced accounts and their names are then empty."}},"required":["id","scopeType","scopeId","sequence","name","actorType","actorId","targetType","targetId","fields","occurredAt","requestId","clientIp","userAgent","labelKey","changeKind","actor","target","scope","changes","references","formerAccounts","peopleHidden"],"additionalProperties":false,"description":"An entry of the audit log."},"description":"Events, newest first."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"One page of results."},"example":{"items":[{"id":"01929b1f-5fc2-7fa6-97c3-bea0a18bd2e3","scopeType":"organization","scopeId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","sequence":42,"name":"role.assigned","actorType":"account","actorId":"01929b1e-8d4b-7e3f-a05c-4d3e2f1a6b7c","targetType":"roleAssignment","targetId":"01929b1e-9e5c-7f40-b16d-5e4f3a2b7c8d","fields":{"role":"Handbook editors","principalKind":"group","principalId":"01929b1f-0a6d-7a51-827e-6f5a4b3c8d9e"},"occurredAt":"2026-10-01T08:00:00.000Z","requestId":"6f1c2b0e-5d4a-4c3b-9a2f-1e0d9c8b7a6f","clientIp":"203.0.113.7","userAgent":"curl/8.9.1","labelKey":"audit.events.role.assigned","changeKind":"fields","actor":{"type":"account","id":"01929b1e-8d4b-7e3f-a05c-4d3e2f1a6b7c","name":"Olivia Owner","former":false,"serviceAccount":false,"token":null},"target":{"type":"roleAssignment","id":"01929b1e-9e5c-7f40-b16d-5e4f3a2b7c8d","name":null,"former":false},"scope":{"type":"organization","id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","name":"Platform Team"},"changes":[{"property":"role","old":null,"new":"Handbook editors"},{"property":"principalKind","old":null,"new":"group"},{"property":"principalId","old":null,"new":"01929b1f-0a6d-7a51-827e-6f5a4b3c8d9e"}],"references":{"01929b1f-0a6d-7a51-827e-6f5a4b3c8d9e":"Editors"},"formerAccounts":[],"peopleHidden":false}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/instance/audit-events/export":{"get":{"operationId":"audit.exportInstance","summary":"Export audit events of the instance as CSV","description":"Streams all events that match the filters as CSV, newest first. The export itself is recorded in the audit log. Cells that start with a formula character are prefixed with an apostrophe.\n\nRequires the permission `instance.audit.view` on the instance.","tags":["Audit log"],"x-lunedo-permission":{"action":"instance.audit.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"from","in":"query","required":false,"description":"Only events at or after this time. ISO 8601 timestamp; an offset is allowed.","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"description":"Only events before this time. ISO 8601 timestamp; an offset is allowed.","schema":{"type":"string","format":"date-time"}},{"name":"actorId","in":"query","required":false,"description":"Only events of this account.","schema":{"type":"string","format":"uuid"}},{"name":"personId","in":"query","required":false,"description":"Only events about this person: those they did and those that name them as the target or the account or holder concerned.","schema":{"type":"string","format":"uuid"}},{"name":"targetType","in":"query","required":false,"description":"Only events about this kind of object, for example `group`.","schema":{"type":"string","maxLength":100}},{"name":"targetId","in":"query","required":false,"description":"Only events about this object. Combine it with `targetType`.","schema":{"type":"string","maxLength":200}},{"name":"name","in":"query","required":false,"description":"Only events of this type, for example `role.assigned`.","schema":{"type":"string","maxLength":100}},{"name":"organizationId","in":"query","required":false,"description":"Only events of this organization.","schema":{"type":"string","format":"uuid"}},{"name":"level","in":"query","required":false,"description":"`instance` lists only events of the instance itself, without those of organizations. With `personId` it adds the events about that account in its organizations, such as ended sessions or a reset second factor.","schema":{"type":"string","enum":["instance"]}}],"responses":{"200":{"description":"The events as CSV with a header row.","content":{"text/csv":{"schema":{"type":"string"},"example":"time,actor,action,target,scope,changes,occurredAt,name,scopeType,scopeId,actorType,actorId,targetType,targetId,fields,clientIp,userAgent,requestId,sequence,id\r\n\"2026-10-01T08:00:00.000Z\",\"Olivia Owner\",\"role.assigned\",...\r\n"}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/instance/backups":{"get":{"operationId":"backups.overview","summary":"Get the backup settings and state","description":"Shows the target, the schedule, the retention, backups before updates, the latest runs and active warnings. The secret key of an S3 target is never returned.\n\nRequires the permission `instance.operations.view` on the instance.","tags":["Backups"],"x-lunedo-permission":{"action":"instance.operations.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"200":{"description":"Settings and state.","content":{"application/json":{"schema":{"type":"object","properties":{"settings":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether scheduled backups run."},"dailyTime":{"type":"string","description":"Time of the daily backup, HH:MM in the time zone of the instance."},"weeklyDay":{"anyOf":[{"type":"integer","minimum":1,"maximum":7},{"type":"null"}],"description":"Day of the week whose backup is kept as a weekly one, 1 (Monday) to 7 (Sunday), or null."},"monthlyDay":{"anyOf":[{"type":"integer","minimum":1,"maximum":31},{"type":"null"}],"description":"Day of the month whose backup is kept as a monthly one, or null. In shorter months the last day is used."},"retention":{"type":"object","properties":{"daily":{"type":"integer","minimum":1,"maximum":1000,"description":"Daily backups to keep."},"weekly":{"type":"integer","minimum":1,"maximum":1000,"description":"Weekly backups to keep."},"monthly":{"type":"integer","minimum":1,"maximum":1000,"description":"Monthly backups to keep."},"beforeUpdate":{"type":"integer","minimum":1,"maximum":1000,"description":"Backups before updates to keep."}},"required":["daily","weekly","monthly","beforeUpdate"],"additionalProperties":false,"description":"How many backups of each class are kept. Manual backups are kept until they are deleted."},"scope":{"type":"string","enum":["all","database"],"description":"`all`: database, file store and configuration. `database`: without the file store."},"beforeUpdate":{"type":"boolean","description":"Whether a backup is taken before migrations run."},"missingDays":{"type":"integer","minimum":1,"maximum":365,"description":"Days without a successful backup after which administrators are warned."},"autoTestRestore":{"type":"boolean","description":"Whether the newest backup is test-restored once a month."}},"required":["enabled","dailyTime","weeklyDay","monthlyDay","retention","scope","beforeUpdate","missingDays","autoTestRestore"],"additionalProperties":false,"description":"The backup settings."},"restoredAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When this instance was restored from a backup while its target is not confirmed yet. Scheduled backups, retention and the monthly test restore are paused until an instance administrator confirms or changes the target; null otherwise. ISO 8601 timestamp in UTC."},"target":{"anyOf":[{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"local","description":"A directory inside the container, also a mounted network share."},"path":{"type":"string","description":"Absolute path of the directory."},"sameVolumeAsFiles":{"type":"boolean","description":"Whether the directory is on the same volume as the file store, so one disk failure loses both."}},"required":["kind","path","sameVolumeAsFiles"],"additionalProperties":false,"description":"A local backup target."},{"type":"object","properties":{"kind":{"type":"string","const":"s3","description":"S3-compatible storage."},"endpoint":{"description":"Address of the service, or null for Amazon S3.","type":["string","null"]},"region":{"type":"string","description":"Region of the bucket."},"bucket":{"type":"string","description":"Bucket name."},"prefix":{"type":"string","description":"Prefix of the object names, empty or ending with a slash."},"forcePathStyle":{"type":"boolean","description":"Whether the bucket is addressed in the path."},"accessKeyId":{"type":"string","description":"Access key."},"secretKeyConfigured":{"type":"boolean","description":"Whether a secret key is stored. It is never returned."}},"required":["kind","endpoint","region","bucket","prefix","forcePathStyle","accessKeyId","secretKeyConfigured"],"additionalProperties":false,"description":"An S3-compatible backup target."}]},{"type":"null"}],"description":"The target, or null."},"timeZone":{"type":"string","description":"Time zone of the instance, in which the daily time applies."},"nextRunAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the next scheduled backup starts, or null when backups are off. ISO 8601 timestamp in UTC."},"beforeUpdate":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether a backup is taken before migrations."},"disabledBy":{"anyOf":[{"type":"string","enum":["setting","environment"]},{"type":"null"}],"description":"What turned it off: the setting, or LUNEDO_BACKUP_BEFORE_UPDATE."}},"required":["enabled","disabledBy"],"additionalProperties":false,"description":"Backups before updates."},"keyConfirmed":{"anyOf":[{"type":"object","properties":{"at":{"type":"string","description":"When it was confirmed. ISO 8601 timestamp in UTC."},"by":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"Account ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who confirmed it."},"inSetup":{"type":"boolean","description":"Whether it was confirmed in the setup, when the keys were downloaded."}},"required":["at","by","inSetup"],"additionalProperties":false},{"type":"null"}],"description":"When an administrator confirmed that the backup key is stored outside Lunedo."},"running":{"type":"boolean","description":"Whether a backup is running now."},"testRestoreRunning":{"type":"boolean","description":"Whether a test restore is running now."},"alert":{"type":"string","enum":["none","failing","missing"],"description":"Active warning: backups fail, or no backup succeeded for the configured days."},"warning":{"anyOf":[{"type":"string","enum":["off","noTarget"]},{"type":"null"}],"description":"Why the admin area shows a banner while the instance has content: backups are off, or no target."},"lastSuccess":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"ID of the run."},"trigger":{"type":"string","enum":["scheduled","manual","beforeUpdate"],"description":"What started the run."},"backupClass":{"type":"string","enum":["daily","weekly","monthly","manual","beforeUpdate"],"description":"Retention class of the backup."},"state":{"type":"string","enum":["running","succeeded","failed","skipped"],"description":"State of the run."},"name":{"description":"Name of the backup, once written.","type":["string","null"]},"sizeBytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size of the backup in bytes, once written."},"error":{"description":"Why the run failed or was skipped.","type":["string","null"]},"startedAt":{"type":"string","description":"When the run started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the run ended. ISO 8601 timestamp in UTC."}},"required":["id","trigger","backupClass","state","name","sizeBytes","error","startedAt","finishedAt"],"additionalProperties":false},{"type":"null"}],"description":"A backup run."},"lastFailure":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"ID of the run."},"trigger":{"type":"string","enum":["scheduled","manual","beforeUpdate"],"description":"What started the run."},"backupClass":{"type":"string","enum":["daily","weekly","monthly","manual","beforeUpdate"],"description":"Retention class of the backup."},"state":{"type":"string","enum":["running","succeeded","failed","skipped"],"description":"State of the run."},"name":{"description":"Name of the backup, once written.","type":["string","null"]},"sizeBytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size of the backup in bytes, once written."},"error":{"description":"Why the run failed or was skipped.","type":["string","null"]},"startedAt":{"type":"string","description":"When the run started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the run ended. ISO 8601 timestamp in UTC."}},"required":["id","trigger","backupClass","state","name","sizeBytes","error","startedAt","finishedAt"],"additionalProperties":false},{"type":"null"}],"description":"A backup run."},"runs":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"ID of the run."},"trigger":{"type":"string","enum":["scheduled","manual","beforeUpdate"],"description":"What started the run."},"backupClass":{"type":"string","enum":["daily","weekly","monthly","manual","beforeUpdate"],"description":"Retention class of the backup."},"state":{"type":"string","enum":["running","succeeded","failed","skipped"],"description":"State of the run."},"name":{"description":"Name of the backup, once written.","type":["string","null"]},"sizeBytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size of the backup in bytes, once written."},"error":{"description":"Why the run failed or was skipped.","type":["string","null"]},"startedAt":{"type":"string","description":"When the run started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the run ended. ISO 8601 timestamp in UTC."}},"required":["id","trigger","backupClass","state","name","sizeBytes","error","startedAt","finishedAt"],"additionalProperties":false,"description":"A backup run."},"description":"The latest runs, newest first."}},"required":["settings","restoredAt","target","timeZone","nextRunAt","beforeUpdate","keyConfirmed","running","testRestoreRunning","alert","warning","lastSuccess","lastFailure","runs"],"additionalProperties":false,"description":"Settings and state of the backups."},"example":{"settings":{"enabled":true,"dailyTime":"02:00","weeklyDay":7,"monthlyDay":1,"retention":{"daily":7,"weekly":4,"monthly":6,"beforeUpdate":3},"scope":"all","beforeUpdate":true,"missingDays":2,"autoTestRestore":true},"target":{"kind":"s3","endpoint":"https://s3.example.org","region":"eu-central-1","bucket":"lunedo-backups","prefix":"lunedo/","forcePathStyle":false,"accessKeyId":"AKIAEXAMPLE","secretKeyConfigured":true},"restoredAt":null,"timeZone":"Europe/Vienna","nextRunAt":"2026-10-22T00:00:00.000Z","beforeUpdate":{"enabled":true,"disabledBy":null},"keyConfirmed":{"at":"2026-10-01T09:00:00.000Z","by":{"id":"0192f0e0-1a2b-7c3d-8e4f-5a6b7c8d9e03","name":"Olivia Owner"},"inSetup":false},"running":false,"testRestoreRunning":false,"alert":"none","warning":null,"lastSuccess":{"id":"0192f0e0-1a2b-7c3d-8e4f-5a6b7c8d9e01","trigger":"scheduled","backupClass":"daily","state":"succeeded","name":"lunedo-backup-20261021T000000Z-daily-3f0c8a1b.ldbak","sizeBytes":524288000,"error":null,"startedAt":"2026-10-21T00:00:02.000Z","finishedAt":"2026-10-21T00:04:41.000Z"},"lastFailure":null,"runs":[{"id":"0192f0e0-1a2b-7c3d-8e4f-5a6b7c8d9e01","trigger":"scheduled","backupClass":"daily","state":"succeeded","name":"lunedo-backup-20261021T000000Z-daily-3f0c8a1b.ldbak","sizeBytes":524288000,"error":null,"startedAt":"2026-10-21T00:00:02.000Z","finishedAt":"2026-10-21T00:04:41.000Z"}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/instance/backups/files":{"get":{"operationId":"backups.list","summary":"List the backups in the target","description":"Lists the backups Lunedo created in the target, with class, size, version and the latest test restore. Backups are never downloaded through the API.\n\nRequires the permission `instance.operations.view` on the instance.","tags":["Backups"],"x-lunedo-permission":{"action":"instance.operations.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"200":{"description":"The backups.","content":{"application/json":{"schema":{"type":"object","properties":{"available":{"type":"boolean","description":"Whether the target could be read."},"error":{"description":"Why the target could not be read.","type":["string","null"]},"backups":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the backup in the target."},"backupClass":{"type":"string","enum":["daily","weekly","monthly","manual","beforeUpdate"],"description":"Retention class."},"createdAt":{"type":"string","description":"When it was created. ISO 8601 timestamp in UTC."},"sizeBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size in bytes."},"readable":{"type":"boolean","description":"Whether its header could be read."},"lunedoVersion":{"description":"Lunedo version that created it.","type":["string","null"]},"schemaVersion":{"description":"Schema version of the database in it.","type":["string","null"]},"scope":{"anyOf":[{"type":"string","enum":["all","database"]},{"type":"null"}],"description":"What it contains."},"testRestore":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"ID of the test restore."},"trigger":{"type":"string","enum":["manual","automatic"],"description":"Whether an administrator or the monthly schedule started it."},"state":{"type":"string","enum":["running","passed","verified","failed"],"description":"`passed`: restored and checked. `verified`: only verified, because the database user may not create databases or the work directory has too little free space (see `error`). `failed`: see `error`."},"stage":{"type":"string","enum":["verify","restore","checks","done"],"description":"How far it got."},"checks":{"type":"array","items":{"type":"object","properties":{"check":{"type":"string","enum":["verify","space","privilege","restore","schemaVersion","rows","files"],"description":"What was checked."},"passed":{"type":"boolean","description":"Whether the check passed."},"detail":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":["string","number","boolean","null"]},"description":"Details, for example row counts or the SQL that grants the missing privilege."}},"required":["check","passed","detail"],"additionalProperties":false,"description":"One check of a test restore."},"description":"What was checked."},"error":{"description":"Why it failed.","type":["string","null"]},"actor":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"Account ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who started it, or null for the monthly test restore."},"startedAt":{"type":"string","description":"When it started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When it ended. ISO 8601 timestamp in UTC."}},"required":["id","trigger","state","stage","checks","error","actor","startedAt","finishedAt"],"additionalProperties":false,"description":"A test restore of a backup."},{"type":"null"}],"description":"The latest test restore, or null."}},"required":["name","backupClass","createdAt","sizeBytes","readable","lunedoVersion","schemaVersion","scope","testRestore"],"additionalProperties":false,"description":"A backup."},"description":"Backups Lunedo created in the target, newest first."}},"required":["available","error","backups"],"additionalProperties":false,"description":"Backups in the target."},"example":{"available":true,"error":null,"backups":[{"name":"lunedo-backup-20261021T000000Z-daily-3f0c8a1b.ldbak","backupClass":"daily","createdAt":"2026-10-21T00:00:03.000Z","sizeBytes":524288000,"readable":true,"lunedoVersion":"1.0.0","schemaVersion":"0000_baseline","scope":"all","testRestore":{"id":"0192f0e0-1a2b-7c3d-8e4f-5a6b7c8d9e02","trigger":"manual","state":"passed","stage":"done","checks":[{"check":"verify","passed":true,"detail":{"entries":1204,"schemaVersion":"0000_baseline"}},{"check":"restore","passed":true,"detail":{"database":"lunedo_test_restore_3f0c8a1b9d2e"}},{"check":"schemaVersion","passed":true,"detail":{"expected":"0000_baseline","appliedMigrations":1}},{"check":"rows","passed":true,"detail":{"instance":1,"accounts":42,"spaces":12,"tree_items":1830}},{"check":"files","passed":true,"detail":{"included":true,"referenced":960,"missing":0,"firstMissing":null}}],"error":null,"actor":{"id":"0192f0e0-1a2b-7c3d-8e4f-5a6b7c8d9e03","name":"Olivia Owner"},"startedAt":"2026-10-21T08:00:00.000Z","finishedAt":"2026-10-21T08:06:12.000Z"}}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/instance/backups/files/{name}":{"delete":{"operationId":"backups.remove","summary":"Delete a backup","description":"Deletes a backup Lunedo created from the target. This cannot be undone. Deletions are audited.\n\nRequires the permission `instance.operations.manage` on the instance.","tags":["Backups"],"x-lunedo-permission":{"action":"instance.operations.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"name","in":"path","required":true,"description":"Name of the backup.","schema":{"type":"string","pattern":"^lunedo-backup-\\d{8}T\\d{6}Z-(daily|weekly|monthly|manual|before-update)-[0-9a-f]{8}\\.ldbak$"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidBackupSettings`: The backup settings are not valid. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidBackupSettings":{"value":{"type":"urn:lunedo:problem:invalidBackupSettings","title":"The backup settings are not valid","status":400,"code":"invalidBackupSettings"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`backupNotFound`: The backup is not in the backup target. `notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"backupNotFound":{"value":{"type":"urn:lunedo:problem:backupNotFound","title":"The backup is not in the backup target","status":404,"code":"backupNotFound"}},"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"502":{"description":"`backupTargetFailed`: The backup target could not be used.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"backupTargetFailed":{"value":{"type":"urn:lunedo:problem:backupTargetFailed","title":"The backup target could not be used","status":502,"code":"backupTargetFailed"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/backups/files/{name}/test-restore":{"post":{"operationId":"backups.testRestore","summary":"Test-restore a backup","description":"Verifies the backup and, where the database user may create databases, restores it into a temporary database and directory, checks it and removes both. The result is kept with the backup.\n\nRequires the permission `instance.operations.manage` on the instance.","tags":["Backups"],"x-lunedo-permission":{"action":"instance.operations.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"name","in":"path","required":true,"description":"Name of the backup.","schema":{"type":"string","pattern":"^lunedo-backup-\\d{8}T\\d{6}Z-(daily|weekly|monthly|manual|before-update)-[0-9a-f]{8}\\.ldbak$"}}],"responses":{"202":{"description":"The started test restore.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"ID of the test restore."}},"required":["id"],"additionalProperties":false,"description":"The started test restore."},"example":{"id":"0192f0e0-1a2b-7c3d-8e4f-5a6b7c8d9e02"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidBackupSettings`: The backup settings are not valid. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidBackupSettings":{"value":{"type":"urn:lunedo:problem:invalidBackupSettings","title":"The backup settings are not valid","status":400,"code":"invalidBackupSettings"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`backupNotFound`: The backup is not in the backup target. `notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"backupNotFound":{"value":{"type":"urn:lunedo:problem:backupNotFound","title":"The backup is not in the backup target","status":404,"code":"backupNotFound"}},"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`backupRunning`: A backup or test restore is already running.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"backupRunning":{"value":{"type":"urn:lunedo:problem:backupRunning","title":"A backup or test restore is already running","status":409,"code":"backupRunning"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"502":{"description":"`backupTargetFailed`: The backup target could not be used.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"backupTargetFailed":{"value":{"type":"urn:lunedo:problem:backupTargetFailed","title":"The backup target could not be used","status":502,"code":"backupTargetFailed"}}}}}}}}},"/api/v1/instance/backups/key-confirmation":{"put":{"operationId":"backups.confirmKey","summary":"Confirm that the backup key is stored elsewhere","description":"Records when and by whom it was confirmed that the backup key is kept outside Lunedo, or withdraws it. A backup cannot be restored without this key.\n\nRequires the permission `instance.operations.manage` on the instance.","tags":["Backups"],"x-lunedo-permission":{"action":"instance.operations.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"confirmed":{"type":"boolean","description":"Whether the backup key is stored outside Lunedo."}},"required":["confirmed"],"additionalProperties":false,"description":"Confirms or withdraws that the backup key is stored elsewhere."},"example":{"confirmed":true}}}},"responses":{"200":{"description":"Settings and state.","content":{"application/json":{"schema":{"type":"object","properties":{"settings":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether scheduled backups run."},"dailyTime":{"type":"string","description":"Time of the daily backup, HH:MM in the time zone of the instance."},"weeklyDay":{"anyOf":[{"type":"integer","minimum":1,"maximum":7},{"type":"null"}],"description":"Day of the week whose backup is kept as a weekly one, 1 (Monday) to 7 (Sunday), or null."},"monthlyDay":{"anyOf":[{"type":"integer","minimum":1,"maximum":31},{"type":"null"}],"description":"Day of the month whose backup is kept as a monthly one, or null. In shorter months the last day is used."},"retention":{"type":"object","properties":{"daily":{"type":"integer","minimum":1,"maximum":1000,"description":"Daily backups to keep."},"weekly":{"type":"integer","minimum":1,"maximum":1000,"description":"Weekly backups to keep."},"monthly":{"type":"integer","minimum":1,"maximum":1000,"description":"Monthly backups to keep."},"beforeUpdate":{"type":"integer","minimum":1,"maximum":1000,"description":"Backups before updates to keep."}},"required":["daily","weekly","monthly","beforeUpdate"],"additionalProperties":false,"description":"How many backups of each class are kept. Manual backups are kept until they are deleted."},"scope":{"type":"string","enum":["all","database"],"description":"`all`: database, file store and configuration. `database`: without the file store."},"beforeUpdate":{"type":"boolean","description":"Whether a backup is taken before migrations run."},"missingDays":{"type":"integer","minimum":1,"maximum":365,"description":"Days without a successful backup after which administrators are warned."},"autoTestRestore":{"type":"boolean","description":"Whether the newest backup is test-restored once a month."}},"required":["enabled","dailyTime","weeklyDay","monthlyDay","retention","scope","beforeUpdate","missingDays","autoTestRestore"],"additionalProperties":false,"description":"The backup settings."},"restoredAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When this instance was restored from a backup while its target is not confirmed yet. Scheduled backups, retention and the monthly test restore are paused until an instance administrator confirms or changes the target; null otherwise. ISO 8601 timestamp in UTC."},"target":{"anyOf":[{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"local","description":"A directory inside the container, also a mounted network share."},"path":{"type":"string","description":"Absolute path of the directory."},"sameVolumeAsFiles":{"type":"boolean","description":"Whether the directory is on the same volume as the file store, so one disk failure loses both."}},"required":["kind","path","sameVolumeAsFiles"],"additionalProperties":false,"description":"A local backup target."},{"type":"object","properties":{"kind":{"type":"string","const":"s3","description":"S3-compatible storage."},"endpoint":{"description":"Address of the service, or null for Amazon S3.","type":["string","null"]},"region":{"type":"string","description":"Region of the bucket."},"bucket":{"type":"string","description":"Bucket name."},"prefix":{"type":"string","description":"Prefix of the object names, empty or ending with a slash."},"forcePathStyle":{"type":"boolean","description":"Whether the bucket is addressed in the path."},"accessKeyId":{"type":"string","description":"Access key."},"secretKeyConfigured":{"type":"boolean","description":"Whether a secret key is stored. It is never returned."}},"required":["kind","endpoint","region","bucket","prefix","forcePathStyle","accessKeyId","secretKeyConfigured"],"additionalProperties":false,"description":"An S3-compatible backup target."}]},{"type":"null"}],"description":"The target, or null."},"timeZone":{"type":"string","description":"Time zone of the instance, in which the daily time applies."},"nextRunAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the next scheduled backup starts, or null when backups are off. ISO 8601 timestamp in UTC."},"beforeUpdate":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether a backup is taken before migrations."},"disabledBy":{"anyOf":[{"type":"string","enum":["setting","environment"]},{"type":"null"}],"description":"What turned it off: the setting, or LUNEDO_BACKUP_BEFORE_UPDATE."}},"required":["enabled","disabledBy"],"additionalProperties":false,"description":"Backups before updates."},"keyConfirmed":{"anyOf":[{"type":"object","properties":{"at":{"type":"string","description":"When it was confirmed. ISO 8601 timestamp in UTC."},"by":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"Account ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who confirmed it."},"inSetup":{"type":"boolean","description":"Whether it was confirmed in the setup, when the keys were downloaded."}},"required":["at","by","inSetup"],"additionalProperties":false},{"type":"null"}],"description":"When an administrator confirmed that the backup key is stored outside Lunedo."},"running":{"type":"boolean","description":"Whether a backup is running now."},"testRestoreRunning":{"type":"boolean","description":"Whether a test restore is running now."},"alert":{"type":"string","enum":["none","failing","missing"],"description":"Active warning: backups fail, or no backup succeeded for the configured days."},"warning":{"anyOf":[{"type":"string","enum":["off","noTarget"]},{"type":"null"}],"description":"Why the admin area shows a banner while the instance has content: backups are off, or no target."},"lastSuccess":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"ID of the run."},"trigger":{"type":"string","enum":["scheduled","manual","beforeUpdate"],"description":"What started the run."},"backupClass":{"type":"string","enum":["daily","weekly","monthly","manual","beforeUpdate"],"description":"Retention class of the backup."},"state":{"type":"string","enum":["running","succeeded","failed","skipped"],"description":"State of the run."},"name":{"description":"Name of the backup, once written.","type":["string","null"]},"sizeBytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size of the backup in bytes, once written."},"error":{"description":"Why the run failed or was skipped.","type":["string","null"]},"startedAt":{"type":"string","description":"When the run started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the run ended. ISO 8601 timestamp in UTC."}},"required":["id","trigger","backupClass","state","name","sizeBytes","error","startedAt","finishedAt"],"additionalProperties":false},{"type":"null"}],"description":"A backup run."},"lastFailure":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"ID of the run."},"trigger":{"type":"string","enum":["scheduled","manual","beforeUpdate"],"description":"What started the run."},"backupClass":{"type":"string","enum":["daily","weekly","monthly","manual","beforeUpdate"],"description":"Retention class of the backup."},"state":{"type":"string","enum":["running","succeeded","failed","skipped"],"description":"State of the run."},"name":{"description":"Name of the backup, once written.","type":["string","null"]},"sizeBytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size of the backup in bytes, once written."},"error":{"description":"Why the run failed or was skipped.","type":["string","null"]},"startedAt":{"type":"string","description":"When the run started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the run ended. ISO 8601 timestamp in UTC."}},"required":["id","trigger","backupClass","state","name","sizeBytes","error","startedAt","finishedAt"],"additionalProperties":false},{"type":"null"}],"description":"A backup run."},"runs":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"ID of the run."},"trigger":{"type":"string","enum":["scheduled","manual","beforeUpdate"],"description":"What started the run."},"backupClass":{"type":"string","enum":["daily","weekly","monthly","manual","beforeUpdate"],"description":"Retention class of the backup."},"state":{"type":"string","enum":["running","succeeded","failed","skipped"],"description":"State of the run."},"name":{"description":"Name of the backup, once written.","type":["string","null"]},"sizeBytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size of the backup in bytes, once written."},"error":{"description":"Why the run failed or was skipped.","type":["string","null"]},"startedAt":{"type":"string","description":"When the run started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the run ended. ISO 8601 timestamp in UTC."}},"required":["id","trigger","backupClass","state","name","sizeBytes","error","startedAt","finishedAt"],"additionalProperties":false,"description":"A backup run."},"description":"The latest runs, newest first."}},"required":["settings","restoredAt","target","timeZone","nextRunAt","beforeUpdate","keyConfirmed","running","testRestoreRunning","alert","warning","lastSuccess","lastFailure","runs"],"additionalProperties":false,"description":"Settings and state of the backups."},"example":{"settings":{"enabled":true,"dailyTime":"02:00","weeklyDay":7,"monthlyDay":1,"retention":{"daily":7,"weekly":4,"monthly":6,"beforeUpdate":3},"scope":"all","beforeUpdate":true,"missingDays":2,"autoTestRestore":true},"target":{"kind":"s3","endpoint":"https://s3.example.org","region":"eu-central-1","bucket":"lunedo-backups","prefix":"lunedo/","forcePathStyle":false,"accessKeyId":"AKIAEXAMPLE","secretKeyConfigured":true},"restoredAt":null,"timeZone":"Europe/Vienna","nextRunAt":"2026-10-22T00:00:00.000Z","beforeUpdate":{"enabled":true,"disabledBy":null},"keyConfirmed":{"at":"2026-10-01T09:00:00.000Z","by":{"id":"0192f0e0-1a2b-7c3d-8e4f-5a6b7c8d9e03","name":"Olivia Owner"},"inSetup":false},"running":false,"testRestoreRunning":false,"alert":"none","warning":null,"lastSuccess":{"id":"0192f0e0-1a2b-7c3d-8e4f-5a6b7c8d9e01","trigger":"scheduled","backupClass":"daily","state":"succeeded","name":"lunedo-backup-20261021T000000Z-daily-3f0c8a1b.ldbak","sizeBytes":524288000,"error":null,"startedAt":"2026-10-21T00:00:02.000Z","finishedAt":"2026-10-21T00:04:41.000Z"},"lastFailure":null,"runs":[{"id":"0192f0e0-1a2b-7c3d-8e4f-5a6b7c8d9e01","trigger":"scheduled","backupClass":"daily","state":"succeeded","name":"lunedo-backup-20261021T000000Z-daily-3f0c8a1b.ldbak","sizeBytes":524288000,"error":null,"startedAt":"2026-10-21T00:00:02.000Z","finishedAt":"2026-10-21T00:04:41.000Z"}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/backups/runs":{"post":{"operationId":"backups.run","summary":"Back up now","description":"Starts a manual backup to the target. Manual backups are kept until they are deleted. The list shows the backup when it is done.\n\nRequires the permission `instance.operations.manage` on the instance.","tags":["Backups"],"x-lunedo-permission":{"action":"instance.operations.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"202":{"description":"Accepted."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidBackupSettings`: The backup settings are not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidBackupSettings":{"value":{"type":"urn:lunedo:problem:invalidBackupSettings","title":"The backup settings are not valid","status":400,"code":"invalidBackupSettings"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"409":{"description":"`backupRunning`: A backup or test restore is already running.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"backupRunning":{"value":{"type":"urn:lunedo:problem:backupRunning","title":"A backup or test restore is already running","status":409,"code":"backupRunning"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"502":{"description":"`backupTargetFailed`: The backup target could not be used.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"backupTargetFailed":{"value":{"type":"urn:lunedo:problem:backupTargetFailed","title":"The backup target could not be used","status":502,"code":"backupTargetFailed"}}}}}}}}},"/api/v1/instance/backups/settings":{"patch":{"operationId":"backups.updateSettings","summary":"Change the backup settings","description":"Changes the schedule, the retention, the scope, backups before updates, the warning period and the monthly test restore. Backups can be turned on only with a target. Changes are audited.\n\nRequires the permission `instance.operations.manage` on the instance.","tags":["Backups"],"x-lunedo-permission":{"action":"instance.operations.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"description":"Whether scheduled backups run.","type":"boolean"},"dailyTime":{"description":"Time of the daily backup, HH:MM.","type":"string","maxLength":5},"weeklyDay":{"description":"Day of the week 1 to 7, or null.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"monthlyDay":{"description":"Day of the month 1 to 31, or null.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"retention":{"description":"Counts to change.","type":"object","properties":{"daily":{"description":"Daily backups to keep.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekly":{"description":"Weekly backups to keep.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"monthly":{"description":"Monthly backups to keep.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"beforeUpdate":{"description":"Backups before updates to keep.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"additionalProperties":false},"scope":{"description":"What the backups contain.","type":"string","enum":["all","database"]},"beforeUpdate":{"description":"Whether a backup is taken before migrations.","type":"boolean"},"missingDays":{"description":"Days without a backup before a warning.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"autoTestRestore":{"description":"Whether the newest backup is test-restored monthly.","type":"boolean"}},"additionalProperties":false,"description":"Changes to the backup settings. Leave out what stays as it is."},"example":{"enabled":true,"dailyTime":"02:30","weeklyDay":7,"retention":{"daily":7}}}}},"responses":{"200":{"description":"Settings and state.","content":{"application/json":{"schema":{"type":"object","properties":{"settings":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether scheduled backups run."},"dailyTime":{"type":"string","description":"Time of the daily backup, HH:MM in the time zone of the instance."},"weeklyDay":{"anyOf":[{"type":"integer","minimum":1,"maximum":7},{"type":"null"}],"description":"Day of the week whose backup is kept as a weekly one, 1 (Monday) to 7 (Sunday), or null."},"monthlyDay":{"anyOf":[{"type":"integer","minimum":1,"maximum":31},{"type":"null"}],"description":"Day of the month whose backup is kept as a monthly one, or null. In shorter months the last day is used."},"retention":{"type":"object","properties":{"daily":{"type":"integer","minimum":1,"maximum":1000,"description":"Daily backups to keep."},"weekly":{"type":"integer","minimum":1,"maximum":1000,"description":"Weekly backups to keep."},"monthly":{"type":"integer","minimum":1,"maximum":1000,"description":"Monthly backups to keep."},"beforeUpdate":{"type":"integer","minimum":1,"maximum":1000,"description":"Backups before updates to keep."}},"required":["daily","weekly","monthly","beforeUpdate"],"additionalProperties":false,"description":"How many backups of each class are kept. Manual backups are kept until they are deleted."},"scope":{"type":"string","enum":["all","database"],"description":"`all`: database, file store and configuration. `database`: without the file store."},"beforeUpdate":{"type":"boolean","description":"Whether a backup is taken before migrations run."},"missingDays":{"type":"integer","minimum":1,"maximum":365,"description":"Days without a successful backup after which administrators are warned."},"autoTestRestore":{"type":"boolean","description":"Whether the newest backup is test-restored once a month."}},"required":["enabled","dailyTime","weeklyDay","monthlyDay","retention","scope","beforeUpdate","missingDays","autoTestRestore"],"additionalProperties":false,"description":"The backup settings."},"restoredAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When this instance was restored from a backup while its target is not confirmed yet. Scheduled backups, retention and the monthly test restore are paused until an instance administrator confirms or changes the target; null otherwise. ISO 8601 timestamp in UTC."},"target":{"anyOf":[{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"local","description":"A directory inside the container, also a mounted network share."},"path":{"type":"string","description":"Absolute path of the directory."},"sameVolumeAsFiles":{"type":"boolean","description":"Whether the directory is on the same volume as the file store, so one disk failure loses both."}},"required":["kind","path","sameVolumeAsFiles"],"additionalProperties":false,"description":"A local backup target."},{"type":"object","properties":{"kind":{"type":"string","const":"s3","description":"S3-compatible storage."},"endpoint":{"description":"Address of the service, or null for Amazon S3.","type":["string","null"]},"region":{"type":"string","description":"Region of the bucket."},"bucket":{"type":"string","description":"Bucket name."},"prefix":{"type":"string","description":"Prefix of the object names, empty or ending with a slash."},"forcePathStyle":{"type":"boolean","description":"Whether the bucket is addressed in the path."},"accessKeyId":{"type":"string","description":"Access key."},"secretKeyConfigured":{"type":"boolean","description":"Whether a secret key is stored. It is never returned."}},"required":["kind","endpoint","region","bucket","prefix","forcePathStyle","accessKeyId","secretKeyConfigured"],"additionalProperties":false,"description":"An S3-compatible backup target."}]},{"type":"null"}],"description":"The target, or null."},"timeZone":{"type":"string","description":"Time zone of the instance, in which the daily time applies."},"nextRunAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the next scheduled backup starts, or null when backups are off. ISO 8601 timestamp in UTC."},"beforeUpdate":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether a backup is taken before migrations."},"disabledBy":{"anyOf":[{"type":"string","enum":["setting","environment"]},{"type":"null"}],"description":"What turned it off: the setting, or LUNEDO_BACKUP_BEFORE_UPDATE."}},"required":["enabled","disabledBy"],"additionalProperties":false,"description":"Backups before updates."},"keyConfirmed":{"anyOf":[{"type":"object","properties":{"at":{"type":"string","description":"When it was confirmed. ISO 8601 timestamp in UTC."},"by":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"Account ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who confirmed it."},"inSetup":{"type":"boolean","description":"Whether it was confirmed in the setup, when the keys were downloaded."}},"required":["at","by","inSetup"],"additionalProperties":false},{"type":"null"}],"description":"When an administrator confirmed that the backup key is stored outside Lunedo."},"running":{"type":"boolean","description":"Whether a backup is running now."},"testRestoreRunning":{"type":"boolean","description":"Whether a test restore is running now."},"alert":{"type":"string","enum":["none","failing","missing"],"description":"Active warning: backups fail, or no backup succeeded for the configured days."},"warning":{"anyOf":[{"type":"string","enum":["off","noTarget"]},{"type":"null"}],"description":"Why the admin area shows a banner while the instance has content: backups are off, or no target."},"lastSuccess":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"ID of the run."},"trigger":{"type":"string","enum":["scheduled","manual","beforeUpdate"],"description":"What started the run."},"backupClass":{"type":"string","enum":["daily","weekly","monthly","manual","beforeUpdate"],"description":"Retention class of the backup."},"state":{"type":"string","enum":["running","succeeded","failed","skipped"],"description":"State of the run."},"name":{"description":"Name of the backup, once written.","type":["string","null"]},"sizeBytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size of the backup in bytes, once written."},"error":{"description":"Why the run failed or was skipped.","type":["string","null"]},"startedAt":{"type":"string","description":"When the run started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the run ended. ISO 8601 timestamp in UTC."}},"required":["id","trigger","backupClass","state","name","sizeBytes","error","startedAt","finishedAt"],"additionalProperties":false},{"type":"null"}],"description":"A backup run."},"lastFailure":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"ID of the run."},"trigger":{"type":"string","enum":["scheduled","manual","beforeUpdate"],"description":"What started the run."},"backupClass":{"type":"string","enum":["daily","weekly","monthly","manual","beforeUpdate"],"description":"Retention class of the backup."},"state":{"type":"string","enum":["running","succeeded","failed","skipped"],"description":"State of the run."},"name":{"description":"Name of the backup, once written.","type":["string","null"]},"sizeBytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size of the backup in bytes, once written."},"error":{"description":"Why the run failed or was skipped.","type":["string","null"]},"startedAt":{"type":"string","description":"When the run started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the run ended. ISO 8601 timestamp in UTC."}},"required":["id","trigger","backupClass","state","name","sizeBytes","error","startedAt","finishedAt"],"additionalProperties":false},{"type":"null"}],"description":"A backup run."},"runs":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"ID of the run."},"trigger":{"type":"string","enum":["scheduled","manual","beforeUpdate"],"description":"What started the run."},"backupClass":{"type":"string","enum":["daily","weekly","monthly","manual","beforeUpdate"],"description":"Retention class of the backup."},"state":{"type":"string","enum":["running","succeeded","failed","skipped"],"description":"State of the run."},"name":{"description":"Name of the backup, once written.","type":["string","null"]},"sizeBytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size of the backup in bytes, once written."},"error":{"description":"Why the run failed or was skipped.","type":["string","null"]},"startedAt":{"type":"string","description":"When the run started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the run ended. ISO 8601 timestamp in UTC."}},"required":["id","trigger","backupClass","state","name","sizeBytes","error","startedAt","finishedAt"],"additionalProperties":false,"description":"A backup run."},"description":"The latest runs, newest first."}},"required":["settings","restoredAt","target","timeZone","nextRunAt","beforeUpdate","keyConfirmed","running","testRestoreRunning","alert","warning","lastSuccess","lastFailure","runs"],"additionalProperties":false,"description":"Settings and state of the backups."},"example":{"settings":{"enabled":true,"dailyTime":"02:00","weeklyDay":7,"monthlyDay":1,"retention":{"daily":7,"weekly":4,"monthly":6,"beforeUpdate":3},"scope":"all","beforeUpdate":true,"missingDays":2,"autoTestRestore":true},"target":{"kind":"s3","endpoint":"https://s3.example.org","region":"eu-central-1","bucket":"lunedo-backups","prefix":"lunedo/","forcePathStyle":false,"accessKeyId":"AKIAEXAMPLE","secretKeyConfigured":true},"restoredAt":null,"timeZone":"Europe/Vienna","nextRunAt":"2026-10-22T00:00:00.000Z","beforeUpdate":{"enabled":true,"disabledBy":null},"keyConfirmed":{"at":"2026-10-01T09:00:00.000Z","by":{"id":"0192f0e0-1a2b-7c3d-8e4f-5a6b7c8d9e03","name":"Olivia Owner"},"inSetup":false},"running":false,"testRestoreRunning":false,"alert":"none","warning":null,"lastSuccess":{"id":"0192f0e0-1a2b-7c3d-8e4f-5a6b7c8d9e01","trigger":"scheduled","backupClass":"daily","state":"succeeded","name":"lunedo-backup-20261021T000000Z-daily-3f0c8a1b.ldbak","sizeBytes":524288000,"error":null,"startedAt":"2026-10-21T00:00:02.000Z","finishedAt":"2026-10-21T00:04:41.000Z"},"lastFailure":null,"runs":[{"id":"0192f0e0-1a2b-7c3d-8e4f-5a6b7c8d9e01","trigger":"scheduled","backupClass":"daily","state":"succeeded","name":"lunedo-backup-20261021T000000Z-daily-3f0c8a1b.ldbak","sizeBytes":524288000,"error":null,"startedAt":"2026-10-21T00:00:02.000Z","finishedAt":"2026-10-21T00:04:41.000Z"}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidBackupSettings`: The backup settings are not valid. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidBackupSettings":{"value":{"type":"urn:lunedo:problem:invalidBackupSettings","title":"The backup settings are not valid","status":400,"code":"invalidBackupSettings"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/backups/status":{"get":{"operationId":"backups.status","summary":"Get a short backup status","description":"Last success, last failure, next run and whether backups and backups before updates are on.\n\nRequires the permission `instance.operations.view` on the instance.","tags":["Backups"],"x-lunedo-permission":{"action":"instance.operations.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"200":{"description":"The status.","content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether scheduled backups run."},"restoredAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When this instance was restored from a backup while its target is not confirmed yet; backups are paused until then. ISO 8601 timestamp in UTC."},"testRestoreCleanupAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When leftovers of an interrupted test restore (a temporary database or directory) were last removed. ISO 8601 timestamp in UTC."},"targetConfigured":{"type":"boolean","description":"Whether a target is set up."},"running":{"type":"boolean","description":"Whether a backup is running now."},"nextRunAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the next scheduled backup starts. ISO 8601 timestamp in UTC."},"lastSuccess":{"anyOf":[{"type":"object","properties":{"at":{"type":"string","description":"When it finished. ISO 8601 timestamp in UTC."},"name":{"description":"Name of the backup.","type":["string","null"]},"sizeBytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes."}},"required":["at","name","sizeBytes"],"additionalProperties":false},{"type":"null"}],"description":"The last successful backup."},"lastFailure":{"anyOf":[{"type":"object","properties":{"at":{"type":"string","description":"When it failed. ISO 8601 timestamp in UTC."},"reason":{"description":"Why.","type":["string","null"]}},"required":["at","reason"],"additionalProperties":false},{"type":"null"}],"description":"The last failed backup."},"alert":{"type":"string","enum":["none","failing","missing"],"description":"Active warning."},"beforeUpdate":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether a backup is taken before migrations."},"disabledBy":{"anyOf":[{"type":"string","enum":["setting","environment"]},{"type":"null"}],"description":"What turned it off."}},"required":["enabled","disabledBy"],"additionalProperties":false,"description":"Backups before updates."}},"required":["enabled","restoredAt","testRestoreCleanupAt","targetConfigured","running","nextRunAt","lastSuccess","lastFailure","alert","beforeUpdate"],"additionalProperties":false,"description":"A short status of the backups, for monitoring."},"example":{"enabled":true,"restoredAt":null,"testRestoreCleanupAt":null,"targetConfigured":true,"running":false,"nextRunAt":"2026-10-22T00:00:00.000Z","lastSuccess":{"at":"2026-10-21T00:04:41.000Z","name":"lunedo-backup-20261021T000000Z-daily-3f0c8a1b.ldbak","sizeBytes":524288000},"lastFailure":null,"alert":"none","beforeUpdate":{"enabled":true,"disabledBy":null}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/instance/backups/target":{"put":{"operationId":"backups.updateTarget","summary":"Set the backup target","description":"Sets the local directory or the S3-compatible storage that backups are written to. The secret key is stored encrypted and never returned; leave it out to keep the stored one. Changes are audited without the secret key.\n\nRequires the permission `instance.operations.manage` on the instance.","tags":["Backups"],"x-lunedo-permission":{"action":"instance.operations.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"local","description":"A directory inside the container."},"path":{"type":"string","maxLength":1024,"description":"Absolute path, for example /var/lib/lunedo/backups."}},"required":["kind","path"],"additionalProperties":false,"description":"A local target."},{"type":"object","properties":{"kind":{"type":"string","const":"s3","description":"S3-compatible storage."},"endpoint":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"description":"Address of the service, or null for Amazon S3."},"region":{"type":"string","maxLength":64,"description":"Region of the bucket, for example eu-central-1 or auto."},"bucket":{"type":"string","maxLength":63,"description":"Bucket name."},"prefix":{"type":"string","maxLength":512,"description":"Prefix of the object names, empty or ending with a slash."},"forcePathStyle":{"type":"boolean","description":"Whether the bucket is addressed in the path, as MinIO needs."},"accessKeyId":{"type":"string","maxLength":256,"description":"Access key."},"secretAccessKey":{"description":"Secret key. Leave it out to keep the stored one. It is stored encrypted and never returned.","type":"string","maxLength":512}},"required":["kind","endpoint","region","bucket","prefix","forcePathStyle","accessKeyId"],"additionalProperties":false,"description":"An S3-compatible target."}],"description":"The backup target."},"example":{"kind":"local","path":"/var/lib/lunedo/backups"}}}},"responses":{"200":{"description":"Settings and state.","content":{"application/json":{"schema":{"type":"object","properties":{"settings":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether scheduled backups run."},"dailyTime":{"type":"string","description":"Time of the daily backup, HH:MM in the time zone of the instance."},"weeklyDay":{"anyOf":[{"type":"integer","minimum":1,"maximum":7},{"type":"null"}],"description":"Day of the week whose backup is kept as a weekly one, 1 (Monday) to 7 (Sunday), or null."},"monthlyDay":{"anyOf":[{"type":"integer","minimum":1,"maximum":31},{"type":"null"}],"description":"Day of the month whose backup is kept as a monthly one, or null. In shorter months the last day is used."},"retention":{"type":"object","properties":{"daily":{"type":"integer","minimum":1,"maximum":1000,"description":"Daily backups to keep."},"weekly":{"type":"integer","minimum":1,"maximum":1000,"description":"Weekly backups to keep."},"monthly":{"type":"integer","minimum":1,"maximum":1000,"description":"Monthly backups to keep."},"beforeUpdate":{"type":"integer","minimum":1,"maximum":1000,"description":"Backups before updates to keep."}},"required":["daily","weekly","monthly","beforeUpdate"],"additionalProperties":false,"description":"How many backups of each class are kept. Manual backups are kept until they are deleted."},"scope":{"type":"string","enum":["all","database"],"description":"`all`: database, file store and configuration. `database`: without the file store."},"beforeUpdate":{"type":"boolean","description":"Whether a backup is taken before migrations run."},"missingDays":{"type":"integer","minimum":1,"maximum":365,"description":"Days without a successful backup after which administrators are warned."},"autoTestRestore":{"type":"boolean","description":"Whether the newest backup is test-restored once a month."}},"required":["enabled","dailyTime","weeklyDay","monthlyDay","retention","scope","beforeUpdate","missingDays","autoTestRestore"],"additionalProperties":false,"description":"The backup settings."},"restoredAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When this instance was restored from a backup while its target is not confirmed yet. Scheduled backups, retention and the monthly test restore are paused until an instance administrator confirms or changes the target; null otherwise. ISO 8601 timestamp in UTC."},"target":{"anyOf":[{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"local","description":"A directory inside the container, also a mounted network share."},"path":{"type":"string","description":"Absolute path of the directory."},"sameVolumeAsFiles":{"type":"boolean","description":"Whether the directory is on the same volume as the file store, so one disk failure loses both."}},"required":["kind","path","sameVolumeAsFiles"],"additionalProperties":false,"description":"A local backup target."},{"type":"object","properties":{"kind":{"type":"string","const":"s3","description":"S3-compatible storage."},"endpoint":{"description":"Address of the service, or null for Amazon S3.","type":["string","null"]},"region":{"type":"string","description":"Region of the bucket."},"bucket":{"type":"string","description":"Bucket name."},"prefix":{"type":"string","description":"Prefix of the object names, empty or ending with a slash."},"forcePathStyle":{"type":"boolean","description":"Whether the bucket is addressed in the path."},"accessKeyId":{"type":"string","description":"Access key."},"secretKeyConfigured":{"type":"boolean","description":"Whether a secret key is stored. It is never returned."}},"required":["kind","endpoint","region","bucket","prefix","forcePathStyle","accessKeyId","secretKeyConfigured"],"additionalProperties":false,"description":"An S3-compatible backup target."}]},{"type":"null"}],"description":"The target, or null."},"timeZone":{"type":"string","description":"Time zone of the instance, in which the daily time applies."},"nextRunAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the next scheduled backup starts, or null when backups are off. ISO 8601 timestamp in UTC."},"beforeUpdate":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether a backup is taken before migrations."},"disabledBy":{"anyOf":[{"type":"string","enum":["setting","environment"]},{"type":"null"}],"description":"What turned it off: the setting, or LUNEDO_BACKUP_BEFORE_UPDATE."}},"required":["enabled","disabledBy"],"additionalProperties":false,"description":"Backups before updates."},"keyConfirmed":{"anyOf":[{"type":"object","properties":{"at":{"type":"string","description":"When it was confirmed. ISO 8601 timestamp in UTC."},"by":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"Account ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who confirmed it."},"inSetup":{"type":"boolean","description":"Whether it was confirmed in the setup, when the keys were downloaded."}},"required":["at","by","inSetup"],"additionalProperties":false},{"type":"null"}],"description":"When an administrator confirmed that the backup key is stored outside Lunedo."},"running":{"type":"boolean","description":"Whether a backup is running now."},"testRestoreRunning":{"type":"boolean","description":"Whether a test restore is running now."},"alert":{"type":"string","enum":["none","failing","missing"],"description":"Active warning: backups fail, or no backup succeeded for the configured days."},"warning":{"anyOf":[{"type":"string","enum":["off","noTarget"]},{"type":"null"}],"description":"Why the admin area shows a banner while the instance has content: backups are off, or no target."},"lastSuccess":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"ID of the run."},"trigger":{"type":"string","enum":["scheduled","manual","beforeUpdate"],"description":"What started the run."},"backupClass":{"type":"string","enum":["daily","weekly","monthly","manual","beforeUpdate"],"description":"Retention class of the backup."},"state":{"type":"string","enum":["running","succeeded","failed","skipped"],"description":"State of the run."},"name":{"description":"Name of the backup, once written.","type":["string","null"]},"sizeBytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size of the backup in bytes, once written."},"error":{"description":"Why the run failed or was skipped.","type":["string","null"]},"startedAt":{"type":"string","description":"When the run started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the run ended. ISO 8601 timestamp in UTC."}},"required":["id","trigger","backupClass","state","name","sizeBytes","error","startedAt","finishedAt"],"additionalProperties":false},{"type":"null"}],"description":"A backup run."},"lastFailure":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"ID of the run."},"trigger":{"type":"string","enum":["scheduled","manual","beforeUpdate"],"description":"What started the run."},"backupClass":{"type":"string","enum":["daily","weekly","monthly","manual","beforeUpdate"],"description":"Retention class of the backup."},"state":{"type":"string","enum":["running","succeeded","failed","skipped"],"description":"State of the run."},"name":{"description":"Name of the backup, once written.","type":["string","null"]},"sizeBytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size of the backup in bytes, once written."},"error":{"description":"Why the run failed or was skipped.","type":["string","null"]},"startedAt":{"type":"string","description":"When the run started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the run ended. ISO 8601 timestamp in UTC."}},"required":["id","trigger","backupClass","state","name","sizeBytes","error","startedAt","finishedAt"],"additionalProperties":false},{"type":"null"}],"description":"A backup run."},"runs":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"ID of the run."},"trigger":{"type":"string","enum":["scheduled","manual","beforeUpdate"],"description":"What started the run."},"backupClass":{"type":"string","enum":["daily","weekly","monthly","manual","beforeUpdate"],"description":"Retention class of the backup."},"state":{"type":"string","enum":["running","succeeded","failed","skipped"],"description":"State of the run."},"name":{"description":"Name of the backup, once written.","type":["string","null"]},"sizeBytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size of the backup in bytes, once written."},"error":{"description":"Why the run failed or was skipped.","type":["string","null"]},"startedAt":{"type":"string","description":"When the run started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the run ended. ISO 8601 timestamp in UTC."}},"required":["id","trigger","backupClass","state","name","sizeBytes","error","startedAt","finishedAt"],"additionalProperties":false,"description":"A backup run."},"description":"The latest runs, newest first."}},"required":["settings","restoredAt","target","timeZone","nextRunAt","beforeUpdate","keyConfirmed","running","testRestoreRunning","alert","warning","lastSuccess","lastFailure","runs"],"additionalProperties":false,"description":"Settings and state of the backups."},"example":{"settings":{"enabled":true,"dailyTime":"02:00","weeklyDay":7,"monthlyDay":1,"retention":{"daily":7,"weekly":4,"monthly":6,"beforeUpdate":3},"scope":"all","beforeUpdate":true,"missingDays":2,"autoTestRestore":true},"target":{"kind":"s3","endpoint":"https://s3.example.org","region":"eu-central-1","bucket":"lunedo-backups","prefix":"lunedo/","forcePathStyle":false,"accessKeyId":"AKIAEXAMPLE","secretKeyConfigured":true},"restoredAt":null,"timeZone":"Europe/Vienna","nextRunAt":"2026-10-22T00:00:00.000Z","beforeUpdate":{"enabled":true,"disabledBy":null},"keyConfirmed":{"at":"2026-10-01T09:00:00.000Z","by":{"id":"0192f0e0-1a2b-7c3d-8e4f-5a6b7c8d9e03","name":"Olivia Owner"},"inSetup":false},"running":false,"testRestoreRunning":false,"alert":"none","warning":null,"lastSuccess":{"id":"0192f0e0-1a2b-7c3d-8e4f-5a6b7c8d9e01","trigger":"scheduled","backupClass":"daily","state":"succeeded","name":"lunedo-backup-20261021T000000Z-daily-3f0c8a1b.ldbak","sizeBytes":524288000,"error":null,"startedAt":"2026-10-21T00:00:02.000Z","finishedAt":"2026-10-21T00:04:41.000Z"},"lastFailure":null,"runs":[{"id":"0192f0e0-1a2b-7c3d-8e4f-5a6b7c8d9e01","trigger":"scheduled","backupClass":"daily","state":"succeeded","name":"lunedo-backup-20261021T000000Z-daily-3f0c8a1b.ldbak","sizeBytes":524288000,"error":null,"startedAt":"2026-10-21T00:00:02.000Z","finishedAt":"2026-10-21T00:04:41.000Z"}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidBackupSettings`: The backup settings are not valid. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidBackupSettings":{"value":{"type":"urn:lunedo:problem:invalidBackupSettings","title":"The backup settings are not valid","status":400,"code":"invalidBackupSettings"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/backups/target/confirmation":{"post":{"operationId":"backups.confirmTarget","summary":"Confirm the backup target after a restore","description":"After a restore from a backup, scheduled backups, retention and the monthly test restore are paused, so that a copy of an instance never writes into or deletes from the backups of the original. Confirming the target resumes them. Changing the target resumes them as well. The confirmation is audited.\n\nRequires the permission `instance.operations.manage` on the instance.","tags":["Backups"],"x-lunedo-permission":{"action":"instance.operations.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"200":{"description":"Settings and state.","content":{"application/json":{"schema":{"type":"object","properties":{"settings":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether scheduled backups run."},"dailyTime":{"type":"string","description":"Time of the daily backup, HH:MM in the time zone of the instance."},"weeklyDay":{"anyOf":[{"type":"integer","minimum":1,"maximum":7},{"type":"null"}],"description":"Day of the week whose backup is kept as a weekly one, 1 (Monday) to 7 (Sunday), or null."},"monthlyDay":{"anyOf":[{"type":"integer","minimum":1,"maximum":31},{"type":"null"}],"description":"Day of the month whose backup is kept as a monthly one, or null. In shorter months the last day is used."},"retention":{"type":"object","properties":{"daily":{"type":"integer","minimum":1,"maximum":1000,"description":"Daily backups to keep."},"weekly":{"type":"integer","minimum":1,"maximum":1000,"description":"Weekly backups to keep."},"monthly":{"type":"integer","minimum":1,"maximum":1000,"description":"Monthly backups to keep."},"beforeUpdate":{"type":"integer","minimum":1,"maximum":1000,"description":"Backups before updates to keep."}},"required":["daily","weekly","monthly","beforeUpdate"],"additionalProperties":false,"description":"How many backups of each class are kept. Manual backups are kept until they are deleted."},"scope":{"type":"string","enum":["all","database"],"description":"`all`: database, file store and configuration. `database`: without the file store."},"beforeUpdate":{"type":"boolean","description":"Whether a backup is taken before migrations run."},"missingDays":{"type":"integer","minimum":1,"maximum":365,"description":"Days without a successful backup after which administrators are warned."},"autoTestRestore":{"type":"boolean","description":"Whether the newest backup is test-restored once a month."}},"required":["enabled","dailyTime","weeklyDay","monthlyDay","retention","scope","beforeUpdate","missingDays","autoTestRestore"],"additionalProperties":false,"description":"The backup settings."},"restoredAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When this instance was restored from a backup while its target is not confirmed yet. Scheduled backups, retention and the monthly test restore are paused until an instance administrator confirms or changes the target; null otherwise. ISO 8601 timestamp in UTC."},"target":{"anyOf":[{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"local","description":"A directory inside the container, also a mounted network share."},"path":{"type":"string","description":"Absolute path of the directory."},"sameVolumeAsFiles":{"type":"boolean","description":"Whether the directory is on the same volume as the file store, so one disk failure loses both."}},"required":["kind","path","sameVolumeAsFiles"],"additionalProperties":false,"description":"A local backup target."},{"type":"object","properties":{"kind":{"type":"string","const":"s3","description":"S3-compatible storage."},"endpoint":{"description":"Address of the service, or null for Amazon S3.","type":["string","null"]},"region":{"type":"string","description":"Region of the bucket."},"bucket":{"type":"string","description":"Bucket name."},"prefix":{"type":"string","description":"Prefix of the object names, empty or ending with a slash."},"forcePathStyle":{"type":"boolean","description":"Whether the bucket is addressed in the path."},"accessKeyId":{"type":"string","description":"Access key."},"secretKeyConfigured":{"type":"boolean","description":"Whether a secret key is stored. It is never returned."}},"required":["kind","endpoint","region","bucket","prefix","forcePathStyle","accessKeyId","secretKeyConfigured"],"additionalProperties":false,"description":"An S3-compatible backup target."}]},{"type":"null"}],"description":"The target, or null."},"timeZone":{"type":"string","description":"Time zone of the instance, in which the daily time applies."},"nextRunAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the next scheduled backup starts, or null when backups are off. ISO 8601 timestamp in UTC."},"beforeUpdate":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether a backup is taken before migrations."},"disabledBy":{"anyOf":[{"type":"string","enum":["setting","environment"]},{"type":"null"}],"description":"What turned it off: the setting, or LUNEDO_BACKUP_BEFORE_UPDATE."}},"required":["enabled","disabledBy"],"additionalProperties":false,"description":"Backups before updates."},"keyConfirmed":{"anyOf":[{"type":"object","properties":{"at":{"type":"string","description":"When it was confirmed. ISO 8601 timestamp in UTC."},"by":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"Account ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who confirmed it."},"inSetup":{"type":"boolean","description":"Whether it was confirmed in the setup, when the keys were downloaded."}},"required":["at","by","inSetup"],"additionalProperties":false},{"type":"null"}],"description":"When an administrator confirmed that the backup key is stored outside Lunedo."},"running":{"type":"boolean","description":"Whether a backup is running now."},"testRestoreRunning":{"type":"boolean","description":"Whether a test restore is running now."},"alert":{"type":"string","enum":["none","failing","missing"],"description":"Active warning: backups fail, or no backup succeeded for the configured days."},"warning":{"anyOf":[{"type":"string","enum":["off","noTarget"]},{"type":"null"}],"description":"Why the admin area shows a banner while the instance has content: backups are off, or no target."},"lastSuccess":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"ID of the run."},"trigger":{"type":"string","enum":["scheduled","manual","beforeUpdate"],"description":"What started the run."},"backupClass":{"type":"string","enum":["daily","weekly","monthly","manual","beforeUpdate"],"description":"Retention class of the backup."},"state":{"type":"string","enum":["running","succeeded","failed","skipped"],"description":"State of the run."},"name":{"description":"Name of the backup, once written.","type":["string","null"]},"sizeBytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size of the backup in bytes, once written."},"error":{"description":"Why the run failed or was skipped.","type":["string","null"]},"startedAt":{"type":"string","description":"When the run started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the run ended. ISO 8601 timestamp in UTC."}},"required":["id","trigger","backupClass","state","name","sizeBytes","error","startedAt","finishedAt"],"additionalProperties":false},{"type":"null"}],"description":"A backup run."},"lastFailure":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"ID of the run."},"trigger":{"type":"string","enum":["scheduled","manual","beforeUpdate"],"description":"What started the run."},"backupClass":{"type":"string","enum":["daily","weekly","monthly","manual","beforeUpdate"],"description":"Retention class of the backup."},"state":{"type":"string","enum":["running","succeeded","failed","skipped"],"description":"State of the run."},"name":{"description":"Name of the backup, once written.","type":["string","null"]},"sizeBytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size of the backup in bytes, once written."},"error":{"description":"Why the run failed or was skipped.","type":["string","null"]},"startedAt":{"type":"string","description":"When the run started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the run ended. ISO 8601 timestamp in UTC."}},"required":["id","trigger","backupClass","state","name","sizeBytes","error","startedAt","finishedAt"],"additionalProperties":false},{"type":"null"}],"description":"A backup run."},"runs":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"ID of the run."},"trigger":{"type":"string","enum":["scheduled","manual","beforeUpdate"],"description":"What started the run."},"backupClass":{"type":"string","enum":["daily","weekly","monthly","manual","beforeUpdate"],"description":"Retention class of the backup."},"state":{"type":"string","enum":["running","succeeded","failed","skipped"],"description":"State of the run."},"name":{"description":"Name of the backup, once written.","type":["string","null"]},"sizeBytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size of the backup in bytes, once written."},"error":{"description":"Why the run failed or was skipped.","type":["string","null"]},"startedAt":{"type":"string","description":"When the run started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the run ended. ISO 8601 timestamp in UTC."}},"required":["id","trigger","backupClass","state","name","sizeBytes","error","startedAt","finishedAt"],"additionalProperties":false,"description":"A backup run."},"description":"The latest runs, newest first."}},"required":["settings","restoredAt","target","timeZone","nextRunAt","beforeUpdate","keyConfirmed","running","testRestoreRunning","alert","warning","lastSuccess","lastFailure","runs"],"additionalProperties":false,"description":"Settings and state of the backups."},"example":{"settings":{"enabled":true,"dailyTime":"02:00","weeklyDay":7,"monthlyDay":1,"retention":{"daily":7,"weekly":4,"monthly":6,"beforeUpdate":3},"scope":"all","beforeUpdate":true,"missingDays":2,"autoTestRestore":true},"target":{"kind":"s3","endpoint":"https://s3.example.org","region":"eu-central-1","bucket":"lunedo-backups","prefix":"lunedo/","forcePathStyle":false,"accessKeyId":"AKIAEXAMPLE","secretKeyConfigured":true},"restoredAt":null,"timeZone":"Europe/Vienna","nextRunAt":"2026-10-22T00:00:00.000Z","beforeUpdate":{"enabled":true,"disabledBy":null},"keyConfirmed":{"at":"2026-10-01T09:00:00.000Z","by":{"id":"0192f0e0-1a2b-7c3d-8e4f-5a6b7c8d9e03","name":"Olivia Owner"},"inSetup":false},"running":false,"testRestoreRunning":false,"alert":"none","warning":null,"lastSuccess":{"id":"0192f0e0-1a2b-7c3d-8e4f-5a6b7c8d9e01","trigger":"scheduled","backupClass":"daily","state":"succeeded","name":"lunedo-backup-20261021T000000Z-daily-3f0c8a1b.ldbak","sizeBytes":524288000,"error":null,"startedAt":"2026-10-21T00:00:02.000Z","finishedAt":"2026-10-21T00:04:41.000Z"},"lastFailure":null,"runs":[{"id":"0192f0e0-1a2b-7c3d-8e4f-5a6b7c8d9e01","trigger":"scheduled","backupClass":"daily","state":"succeeded","name":"lunedo-backup-20261021T000000Z-daily-3f0c8a1b.ldbak","sizeBytes":524288000,"error":null,"startedAt":"2026-10-21T00:00:02.000Z","finishedAt":"2026-10-21T00:04:41.000Z"}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidBackupSettings`: The backup settings are not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidBackupSettings":{"value":{"type":"urn:lunedo:problem:invalidBackupSettings","title":"The backup settings are not valid","status":400,"code":"invalidBackupSettings"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/backups/target/test":{"post":{"operationId":"backups.testTarget","summary":"Test a backup target","description":"Writes, reads, lists and deletes a small test object with the given settings, without saving them, and says which step failed and why.\n\nRequires the permission `instance.operations.manage` on the instance.","tags":["Backups"],"x-lunedo-permission":{"action":"instance.operations.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"local","description":"A directory inside the container."},"path":{"type":"string","maxLength":1024,"description":"Absolute path, for example /var/lib/lunedo/backups."}},"required":["kind","path"],"additionalProperties":false,"description":"A local target."},{"type":"object","properties":{"kind":{"type":"string","const":"s3","description":"S3-compatible storage."},"endpoint":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"description":"Address of the service, or null for Amazon S3."},"region":{"type":"string","maxLength":64,"description":"Region of the bucket, for example eu-central-1 or auto."},"bucket":{"type":"string","maxLength":63,"description":"Bucket name."},"prefix":{"type":"string","maxLength":512,"description":"Prefix of the object names, empty or ending with a slash."},"forcePathStyle":{"type":"boolean","description":"Whether the bucket is addressed in the path, as MinIO needs."},"accessKeyId":{"type":"string","maxLength":256,"description":"Access key."},"secretAccessKey":{"description":"Secret key. Leave it out to keep the stored one. It is stored encrypted and never returned.","type":"string","maxLength":512}},"required":["kind","endpoint","region","bucket","prefix","forcePathStyle","accessKeyId"],"additionalProperties":false,"description":"An S3-compatible target."}],"description":"The backup target."},"example":{"kind":"s3","endpoint":"https://s3.example.org","region":"eu-central-1","bucket":"lunedo-backups","prefix":"lunedo/","forcePathStyle":false,"accessKeyId":"AKIAEXAMPLE","secretAccessKey":"example-secret-key"}}}},"responses":{"200":{"description":"The result.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","description":"Whether writing, reading, listing and deleting a test object worked."},"failure":{"anyOf":[{"type":"string","enum":["notFound","permission","readOnly","full","dns","blockedAddress","insecureAddress","connection","tls","credentials","bucket","mismatch","other"]},{"type":"null"}],"description":"What failed, or null."},"step":{"anyOf":[{"type":"string","enum":["write","read","delete","list"]},{"type":"null"}],"description":"Which step failed, or null."},"message":{"description":"What failed and what to do, or null.","type":["string","null"]},"blockedAddress":{"description":"The private address the endpoint resolved to when it was refused, or null.","type":["string","null"]},"allowedNetwork":{"description":"The network to add to LUNEDO_OUTBOUND_ALLOWED_NETWORKS so the refused address can be reached, or null.","type":["string","null"]}},"required":["ok","failure","step","message","blockedAddress","allowedNetwork"],"additionalProperties":false,"description":"The result of the connection test."},"example":{"ok":false,"failure":"credentials","step":"write","message":"Writing to the backup target failed: The access key or the secret key was not accepted. Check both keys.","blockedAddress":null,"allowedNetwork":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidBackupSettings`: The backup settings are not valid. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidBackupSettings":{"value":{"type":"urn:lunedo:problem:invalidBackupSettings","title":"The backup settings are not valid","status":400,"code":"invalidBackupSettings"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/backups/test-restores/{id}":{"get":{"operationId":"backups.getTestRestore","summary":"Get a test restore","description":"Shows how far a test restore got and what it checked.\n\nRequires the permission `instance.operations.view` on the instance.","tags":["Backups"],"x-lunedo-permission":{"action":"instance.operations.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"ID of the test restore.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The test restore.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"ID of the test restore."},"trigger":{"type":"string","enum":["manual","automatic"],"description":"Whether an administrator or the monthly schedule started it."},"state":{"type":"string","enum":["running","passed","verified","failed"],"description":"`passed`: restored and checked. `verified`: only verified, because the database user may not create databases or the work directory has too little free space (see `error`). `failed`: see `error`."},"stage":{"type":"string","enum":["verify","restore","checks","done"],"description":"How far it got."},"checks":{"type":"array","items":{"type":"object","properties":{"check":{"type":"string","enum":["verify","space","privilege","restore","schemaVersion","rows","files"],"description":"What was checked."},"passed":{"type":"boolean","description":"Whether the check passed."},"detail":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":["string","number","boolean","null"]},"description":"Details, for example row counts or the SQL that grants the missing privilege."}},"required":["check","passed","detail"],"additionalProperties":false,"description":"One check of a test restore."},"description":"What was checked."},"error":{"description":"Why it failed.","type":["string","null"]},"actor":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"Account ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who started it, or null for the monthly test restore."},"startedAt":{"type":"string","description":"When it started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When it ended. ISO 8601 timestamp in UTC."}},"required":["id","trigger","state","stage","checks","error","actor","startedAt","finishedAt"],"additionalProperties":false,"description":"A test restore of a backup."},"example":{"id":"0192f0e0-1a2b-7c3d-8e4f-5a6b7c8d9e02","trigger":"manual","state":"passed","stage":"done","checks":[{"check":"verify","passed":true,"detail":{"entries":1204,"schemaVersion":"0000_baseline"}},{"check":"restore","passed":true,"detail":{"database":"lunedo_test_restore_3f0c8a1b9d2e"}},{"check":"schemaVersion","passed":true,"detail":{"expected":"0000_baseline","appliedMigrations":1}},{"check":"rows","passed":true,"detail":{"instance":1,"accounts":42,"spaces":12,"tree_items":1830}},{"check":"files","passed":true,"detail":{"included":true,"referenced":960,"missing":0,"firstMissing":null}}],"error":null,"actor":{"id":"0192f0e0-1a2b-7c3d-8e4f-5a6b7c8d9e03","name":"Olivia Owner"},"startedAt":"2026-10-21T08:00:00.000Z","finishedAt":"2026-10-21T08:06:12.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/instance/maintenance":{"get":{"operationId":"operations.maintenanceDetails","summary":"Get the maintenance mode with who changed it","description":"Shows the maintenance mode with when and by whom it was last switched or changed.\n\nRequires the permission `instance.operations.view` on the instance.","tags":["Operations"],"x-lunedo-permission":{"action":"instance.operations.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"200":{"description":"The maintenance mode.","content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether the instance is in maintenance mode and refuses changes."},"message":{"type":"string","description":"The message of the instance administrators shown in the banner. Empty when they wrote none."},"blockSignIn":{"type":"boolean","description":"Whether signing in is paused for everyone except instance administrators."},"startedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When maintenance mode was switched on, or null when it is off."},"changedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When maintenance mode was last switched or changed."},"changedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"type":"string","description":"Display name."}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who changed it last, or null when the command line or no one did."}},"required":["enabled","message","blockSignIn","startedAt","changedAt","changedBy"],"additionalProperties":false,"description":"The maintenance mode of the instance with who changed it."},"example":{"enabled":true,"message":"Update to 1.5 until 18:00. Pages can be read, but not changed.","blockSignIn":false,"startedAt":"2026-10-21T16:00:00.000Z","changedAt":"2026-10-21T16:00:00.000Z","changedBy":{"id":"01929b1e-8d4b-7e3f-a05c-4d3e2f1a6b7c","name":"Olivia Owner"}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"put":{"operationId":"operations.setMaintenance","summary":"Switch maintenance mode","description":"Switches maintenance mode on or off, or changes its message and whether signing in is paused. While it is on, the instance is read-only for everyone, also for instance administrators: changes through the API are refused, open editors switch to read-only, and background jobs that change content wait. Backups, safety-net sweeps, mail delivery, SCIM and identity provider synchronization keep running. With `blockSignIn`, only instance administrators can sign in; existing sessions of others are not ended. Every switch and change is recorded in the audit log.\n\nRequires the permission `instance.operations.manage` on the instance.","tags":["Operations"],"x-lunedo-permission":{"action":"instance.operations.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"`true` switches maintenance mode on or changes its message, `false` switches it off."},"message":{"description":"Message for the banner, at most 500 characters, for example when the maintenance ends.","type":"string","maxLength":500},"blockSignIn":{"description":"Pause signing in for everyone except instance administrators. Existing sessions stay, read-only.","type":"boolean"}},"required":["enabled"],"description":"Switches maintenance mode."},"example":{"enabled":true,"message":"Update to 1.5 until 18:00.","blockSignIn":false}}}},"responses":{"200":{"description":"The maintenance mode after the change.","content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether the instance is in maintenance mode and refuses changes."},"message":{"type":"string","description":"The message of the instance administrators shown in the banner. Empty when they wrote none."},"blockSignIn":{"type":"boolean","description":"Whether signing in is paused for everyone except instance administrators."},"startedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When maintenance mode was switched on, or null when it is off."},"changedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When maintenance mode was last switched or changed."},"changedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"type":"string","description":"Display name."}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who changed it last, or null when the command line or no one did."}},"required":["enabled","message","blockSignIn","startedAt","changedAt","changedBy"],"additionalProperties":false,"description":"The maintenance mode of the instance with who changed it."},"example":{"enabled":true,"message":"Update to 1.5 until 18:00. Pages can be read, but not changed.","blockSignIn":false,"startedAt":"2026-10-21T16:00:00.000Z","changedAt":"2026-10-21T16:00:00.000Z","changedBy":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/instance/operations/status":{"get":{"operationId":"operations.status","summary":"Get the status of the instance","description":"Runs the operations checks: version, database, file storage, job queues, collaboration server, backups, search index, recent errors, and the setup checks for TLS, e-mail, encryption, clock and the file directory. Each item says `ok`, `warning` or `error` with a reason code and where it is fixed.\n\nRequires the permission `instance.operations.view` on the instance.","tags":["Operations"],"x-lunedo-permission":{"action":"instance.operations.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"200":{"description":"The status items.","content":{"application/json":{"schema":{"type":"object","properties":{"checkedAt":{"type":"string","format":"date-time","description":"When the checks ran."},"status":{"type":"string","enum":["ok","warning","error"],"description":"The worst status of all items."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","enum":["version","maintenance","database","storage","jobs","collaboration","backups","searchIndex","recentErrors","tls","email","encryption","clock","fileStorage"],"description":"What the item checks. New items can be added in later versions; clients show unknown items with their status and documentation link."},"status":{"type":"string","enum":["ok","warning","error"],"description":"`ok`, `warning` or `error`."},"reason":{"description":"A stable code for the reason of a warning or error, or a note on an item that is ok, for example `noLimit`. Null when there is nothing to say.","type":["string","null"]},"facts":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":["string","number","boolean","null"]},"description":"Values the item measured, such as sizes in bytes, counts and times. They never contain content or personal data."},"page":{"description":"Path of the settings page where the cause is fixed, or null.","type":["string","null"]},"docs":{"type":"string","description":"Documentation page and section that explains the item."}},"required":["id","status","reason","facts","page","docs"],"additionalProperties":false},"description":"The checked items in a fixed order."},"queues":{"type":"array","items":{"type":"object","properties":{"queue":{"type":"string","description":"Name of the job queue."},"queued":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Jobs waiting to run."},"active":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Jobs running now."},"deferred":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Jobs scheduled for later."},"failed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Jobs that failed after all attempts and are still kept."},"oldestQueuedAt":{"description":"When the oldest waiting job was queued, or null when none waits.","anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["queue","queued","active","deferred","failed"],"additionalProperties":false},"description":"Job queues that have jobs in any state."},"recentErrors":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"The fixed text of the error-level log event. Texts that could contain data are counted as `Other error`."},"code":{"description":"Error code or class name, if the event carried one.","type":["string","null"]},"services":{"type":"array","items":{"type":"string"},"description":"Processes that logged it: `api`, `worker` or `collab`."},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How often it was logged."},"lastAt":{"type":"string","format":"date-time","description":"When it was logged last."}},"required":["type","code","services","count","lastAt"],"additionalProperties":false},"description":"Error-level log events of the last 24 hours by type, newest first, at most 50 types."}},"required":["checkedAt","status","items","queues","recentErrors"],"additionalProperties":false,"description":"The status of the instance."},"example":{"checkedAt":"2026-10-21T08:00:00.000Z","status":"warning","items":[{"id":"version","status":"ok","reason":null,"facts":{"version":"1.4.2"},"page":null,"docs":"admin/monitoring/system-status.md#version"},{"id":"storage","status":"warning","reason":"warning","facts":{"store":"local","usedBytes":86000000000,"totalBytes":100000000000,"percent":86,"level":1},"page":"/settings/instance/storage","docs":"admin/monitoring/system-status.md#storage"}],"queues":[{"queue":"mail.deliver","queued":2,"active":1,"deferred":0,"failed":0,"oldestQueuedAt":"2026-10-24T08:14:00.000Z"}],"recentErrors":[{"type":"Request failed","code":"ECONNRESET","services":["api"],"count":3,"lastAt":"2026-10-21T07:42:10.000Z"}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/instance/organizations":{"get":{"operationId":"instance.organizations","summary":"List all organizations","description":"Lists every organization of the instance with its owners, number of members and domains. `q` searches name and short name.\n\nRequires the permission `instance.organizations.view` on the instance.","tags":["Instance"],"x-lunedo-permission":{"action":"instance.organizations.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}},{"name":"q","in":"query","required":false,"description":"Only items that contain this text, ignoring case: in the name and e-mail address of accounts and members, the name and short name of organizations, and the name and description of groups.","schema":{"type":"string","maxLength":200}}],"responses":{"200":{"description":"Organizations of the instance.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the organization."},"name":{"type":"string","description":"Display name, 1 to 100 characters."},"slug":{"type":"string","description":"Short name used in addresses: lowercase letters, digits and hyphens."},"logoRef":{"description":"Reference to the uploaded logo, or null.","type":["string","null"]},"language":{"type":"string","enum":["en","de"],"description":"Default language of the organization."},"timeZone":{"type":"string","description":"Default IANA time zone, for example `Europe/Vienna`."},"accentColor":{"type":"string","enum":["petrol","blue","violet","amber","red","green","gray"],"description":"Accent color from the palette, from the setting `branding.accentColor`."},"createdAt":{"type":"string","format":"date-time","description":"When the organization was created. ISO 8601 timestamp in UTC."},"owners":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the owner."},"name":{"type":"string","description":"Name of the owner."}},"required":["id","name"],"additionalProperties":false},"description":"Owners of the organization, by name."},"memberCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of active members, collaborators and guests."},"domains":{"type":"array","items":{"type":"string"},"description":"E-mail domains of the organization."}},"required":["id","name","slug","logoRef","language","timeZone","accentColor","createdAt","owners","memberCount","domains"],"additionalProperties":false,"description":"An organization with what instance administrators need to see."},"description":"Organizations, ordered by name."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"One page of results."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","name":"Example Inc.","slug":"example-inc","logoRef":null,"language":"en","timeZone":"Europe/Vienna","accentColor":"petrol","createdAt":"2026-10-01T08:00:00.000Z","owners":[{"id":"01929b1e-8d4b-7e3f-a05c-4d3e2f1a6b7c","name":"Ada Lovelace"}],"memberCount":42,"domains":["example.com"]}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/instance/personal-spaces":{"get":{"operationId":"personalSpaces.review","summary":"List personal spaces to review","description":"Lists personal spaces whose owner is deactivated, with the number of pages and the last change. Instance roles never show titles or content.\n\nRequires the permission `instance.personalSpaces.view` on the instance.","tags":["Spaces"],"x-lunedo-permission":{"action":"instance.personalSpaces.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"Personal spaces to review.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"ID of the personal space."},"key":{"type":"string","description":"Key of the personal space."},"name":{"type":"string","description":"Name of the personal space; empty when it has no name of its own."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of the personal space, or null."},"ownerName":{"description":"Name of the owner, or null.","type":["string","null"]},"ownerState":{"description":"State of the owner's account, such as `deactivated`.","type":["string","null"]},"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of pages in the space."},"remainingMembers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Active members besides the owner. The space can only be transferred to one of them."},"lastChangedAt":{"type":"string","format":"date-time","description":"When the space or one of its pages last changed. ISO 8601 timestamp in UTC."}},"required":["spaceId","key","name","ownerId","ownerName","ownerState","pages","remainingMembers","lastChangedAt"],"additionalProperties":false,"description":"A personal space whose owner is no longer active. Titles and content are not shown."},"description":"Personal spaces, ordered by owner name."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"One page of results."},"example":{"items":[{"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","key":"P7K2M9QX","name":"","ownerId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","ownerName":"Anna Berger","ownerState":"deactivated","pages":12,"remainingMembers":1,"lastChangedAt":"2026-09-30T08:00:00.000Z"}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/instance/personal-spaces/{spaceId}/delete":{"post":{"operationId":"trash.deletePersonalSpace","summary":"Delete a personal space","description":"Deletes a personal space under review. It goes to the second stage of the trash; instance administrators can restore it until that period ends. Requires typing its name or, without a name, its key.\n\nRequires the permission `instance.personalSpaces.manage` on the instance.","tags":["Trash"],"x-lunedo-permission":{"action":"instance.personalSpaces.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the personal space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"confirmation":{"type":"string","maxLength":200,"description":"The name of the space, typed exactly; for a personal space without a name, its key."}},"required":["confirmation"],"additionalProperties":false,"description":"Confirmation of the deletion."},"example":{"confirmation":"~K7Q2"}}}},"responses":{"200":{"description":"The trash entry of the space.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the trash entry."},"spaceId":{"type":"string","format":"uuid","description":"Space of the entry."},"spaceKey":{"type":"string","description":"Key of the space."},"spaceName":{"type":"string","description":"Name of the space."},"kind":{"type":"string","enum":["items","space"],"description":"`items` for deleted pages, folders or links, `space` for a deleted space."},"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The deleted item, or null for a space."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the deleted item in the addresses of the app, or null for a space."},"itemKind":{"anyOf":[{"type":"string","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},{"type":"null"}],"description":"Kind of the deleted item, or null for a space. New values can be added in later versions; handle unknown values."},"title":{"type":"string","description":"Title of the deleted item, or name of the space."},"descendants":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of descendants deleted with the item."},"stage":{"anyOf":[{"type":"number","const":1},{"type":"number","const":2}],"description":"1 while the entry is in the space trash, 2 after that period or after the trash was emptied; then only organization administrators can restore it."},"deletedAt":{"type":"string","format":"date-time","description":"When it was deleted. ISO 8601 timestamp in UTC."},"deletedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when the account no longer exists.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who deleted it."},"stageTwoAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the entry reached stage 2, or null. ISO 8601 timestamp in UTC."},"removedAt":{"type":"string","format":"date-time","description":"When the entry will be deleted permanently, by the current retention settings. ISO 8601 timestamp in UTC."},"formerParentEntryId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The trash entry of the page or folder this item was below, when that one is in the same trash list; restoring with `withParents=true` restores both. Null otherwise."}},"required":["id","spaceId","spaceKey","spaceName","kind","itemId","number","itemKind","title","descendants","stage","deletedAt","deletedBy","stageTwoAt","removedAt","formerParentEntryId"],"additionalProperties":false,"description":"An entry of the trash."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","kind":"space","itemId":null,"number":1041,"itemKind":null,"title":"Old VPN (OpenVPN) setup","descendants":2,"stage":2,"deletedAt":"2026-10-02T10:00:00.000Z","deletedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Lukas Hofer"},"stageTwoAt":null,"removedAt":"2027-02-14T10:00:00.000Z","formerParentEntryId":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `confirmationMismatch`: The confirmation does not match. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"confirmationMismatch":{"value":{"type":"urn:lunedo:problem:confirmationMismatch","title":"The confirmation does not match","status":400,"code":"confirmationMismatch"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/personal-spaces/{spaceId}/remaining-members":{"get":{"operationId":"personalSpaces.transferCandidates","summary":"List who can receive a personal space","description":"Lists the remaining active members of a personal space whose owner is deactivated, without the caller. The space can only be transferred to one of them; without any, only the clean-up remains.\n\nRequires the permission `instance.personalSpaces.manage` on the instance.","tags":["Spaces"],"x-lunedo-permission":{"action":"instance.personalSpaces.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the personal space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The remaining members.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false,"description":"A member."},"description":"Remaining members."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a21","name":"Anna Berger"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/instance/personal-spaces/{spaceId}/transfer":{"post":{"operationId":"personalSpaces.transfer","summary":"Transfer a personal space","description":"Gives a personal space under review to one of its remaining active members, who becomes its space admin. Nobody can transfer a space to themselves. The transfer is audited.\n\nRequires the permission `instance.personalSpaces.manage` on the instance. Needs a signed-in session; API tokens are refused.","tags":["Spaces"],"x-lunedo-permission":{"action":"instance.personalSpaces.manage","resource":"instance"},"security":[{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the personal space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"Remaining active member who receives the space."}},"required":["accountId"],"additionalProperties":false,"description":"The new owner."},"example":{"accountId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a21"}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid. `selfAppointment`: Nobody can give themselves access this way.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"selfAppointment":{"value":{"type":"urn:lunedo:problem:selfAppointment","title":"Nobody can give themselves access this way","status":400,"code":"selfAppointment"}}}}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `reauthenticationRequired`: Confirm your identity first. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"reauthenticationRequired":{"value":{"type":"urn:lunedo:problem:reauthenticationRequired","title":"Confirm your identity first","status":403,"code":"reauthenticationRequired"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notUnderReview`: The personal space is not under review.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notUnderReview":{"value":{"type":"urn:lunedo:problem:notUnderReview","title":"The personal space is not under review","status":409,"code":"notUnderReview"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/personal-spaces/trash":{"get":{"operationId":"trash.personalTrash","summary":"List deleted personal spaces","description":"Lists deleted personal spaces and content of personal spaces in the second stage of the trash, as long as they can be restored.\n\nRequires the permission `instance.personalSpaces.manage` on the instance.","tags":["Trash"],"x-lunedo-permission":{"action":"instance.personalSpaces.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"200":{"description":"Trash entries.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the trash entry."},"spaceId":{"type":"string","format":"uuid","description":"Space of the entry."},"spaceKey":{"type":"string","description":"Key of the space."},"spaceName":{"type":"string","description":"Name of the space."},"kind":{"type":"string","enum":["items","space"],"description":"`items` for deleted pages, folders or links, `space` for a deleted space."},"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The deleted item, or null for a space."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the deleted item in the addresses of the app, or null for a space."},"itemKind":{"anyOf":[{"type":"string","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},{"type":"null"}],"description":"Kind of the deleted item, or null for a space. New values can be added in later versions; handle unknown values."},"title":{"type":"string","description":"Title of the deleted item, or name of the space."},"descendants":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of descendants deleted with the item."},"stage":{"anyOf":[{"type":"number","const":1},{"type":"number","const":2}],"description":"1 while the entry is in the space trash, 2 after that period or after the trash was emptied; then only organization administrators can restore it."},"deletedAt":{"type":"string","format":"date-time","description":"When it was deleted. ISO 8601 timestamp in UTC."},"deletedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when the account no longer exists.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who deleted it."},"stageTwoAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the entry reached stage 2, or null. ISO 8601 timestamp in UTC."},"removedAt":{"type":"string","format":"date-time","description":"When the entry will be deleted permanently, by the current retention settings. ISO 8601 timestamp in UTC."},"formerParentEntryId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The trash entry of the page or folder this item was below, when that one is in the same trash list; restoring with `withParents=true` restores both. Null otherwise."}},"required":["id","spaceId","spaceKey","spaceName","kind","itemId","number","itemKind","title","descendants","stage","deletedAt","deletedBy","stageTwoAt","removedAt","formerParentEntryId"],"additionalProperties":false,"description":"An entry of the trash."},"description":"Trash entries."},"example":[]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/instance/personal-spaces/trash/{entryId}/delete":{"post":{"operationId":"trash.deletePersonal","summary":"Delete a personal space permanently at once","description":"Deletes a deleted personal space permanently without waiting for the retention period. Requires a reason, which goes into the audit log.\n\nRequires the permission `instance.personalSpaces.manage` on the instance. Needs a signed-in session; API tokens are refused.","tags":["Trash"],"x-lunedo-permission":{"action":"instance.personalSpaces.manage","resource":"instance"},"security":[{"sessionCookie":[]}],"parameters":[{"name":"entryId","in":"path","required":true,"description":"ID of the trash entry.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":1000,"description":"Why the content must be deleted at once, for example a legal erasure request. 1 to 500 characters; it goes into the audit log."}},"required":["reason"],"additionalProperties":false,"description":"The reason for deleting permanently at once."},"example":{"reason":"Erasure request of 6 Oct 2026"}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`invalidInput`: The request is not valid. `reasonRequired`: A reason is required.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"reasonRequired":{"value":{"type":"urn:lunedo:problem:reasonRequired","title":"A reason is required","status":400,"code":"reasonRequired"}}}}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `reauthenticationRequired`: Confirm your identity first. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"reauthenticationRequired":{"value":{"type":"urn:lunedo:problem:reauthenticationRequired","title":"Confirm your identity first","status":403,"code":"reauthenticationRequired"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/personal-spaces/trash/{entryId}/restore":{"post":{"operationId":"trash.restorePersonal","summary":"Restore a deleted personal space","description":"Restores a deleted personal space with its content, or content of a personal space in the second stage of the trash. When the former parent page is in the trash and the content would lose a view restriction it inherited, the restore is refused with `restrictedParentInTrash`; repeat it with `withParents=true` to restore the parent pages with it. `withParents=true` also restores a former parent page that is in the trash without a restriction, so the content returns below it.\n\nRequires the permission `instance.personalSpaces.manage` on the instance.","tags":["Trash"],"x-lunedo-permission":{"action":"instance.personalSpaces.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"entryId","in":"path","required":true,"description":"ID of the trash entry.","schema":{"type":"string","format":"uuid"}},{"name":"withParents","in":"query","required":false,"description":"`true` also restores the former parent pages from the trash when the content would otherwise lose a view restriction it inherited. It needs the right to restore each of them.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"The result.","content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The restored item, or null for a space."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the restored item in the addresses of the app, or null for a space."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Where the item went: its parent, or null for the top level."},"parentEntries":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of trash entries of former parent pages restored with it, so it keeps the view restrictions it inherited."}},"required":["itemId","number","parentId","parentEntries"],"additionalProperties":false,"description":"Where the restored content went."},"example":{"itemId":null,"number":null,"parentId":null,"parentEntries":0}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`restrictedParentInTrash`: The content was below a restricted page that is in the trash.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"restrictedParentInTrash":{"value":{"type":"urn:lunedo:problem:restrictedParentInTrash","title":"The content was below a restricted page that is in the trash","status":409,"code":"restrictedParentInTrash"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/portal-domains":{"get":{"operationId":"portal.domains","summary":"List the domains allowed for portals","description":"Domains organizations may use for their knowledge base portals, and which portal uses each.\n\nRequires the permission `instance.settings.manage` on the instance.","tags":["Instance"],"x-lunedo-permission":{"action":"instance.settings.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"200":{"description":"The domains.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"domain":{"type":"string","description":"The domain name."},"organizationId":{"type":"string","format":"uuid","description":"ID of the organization that may use the domain."},"organizationName":{"type":"string","description":"Name of the organization."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the knowledge base that uses the domain."},"spaceName":{"description":"Name of the knowledge base that uses the domain.","type":["string","null"]},"createdAt":{"type":"string","format":"date-time","description":"When the domain was allowed. ISO 8601 timestamp in UTC."}},"required":["domain","organizationId","organizationName","spaceId","spaceName","createdAt"],"additionalProperties":false,"description":"A domain allowed for knowledge base portals."}},"example":[{"domain":"help.example.org","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a30","organizationName":"Example","spaceId":null,"spaceName":null,"createdAt":"2026-10-19T08:00:00.000Z"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"portal.allowDomain","summary":"Allow a domain for portals","description":"Lets one organization use the domain for one of its knowledge base portals. The reverse proxy must send the domain to Lunedo and hold its certificate. The change is recorded in the audit log.\n\nRequires the permission `instance.settings.manage` on the instance.","tags":["Instance"],"x-lunedo-permission":{"action":"instance.settings.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","maxLength":253,"description":"Domain name without https:// and without a path."},"organizationId":{"type":"string","format":"uuid","description":"ID of the organization that may use it."}},"required":["domain","organizationId"],"additionalProperties":false,"description":"A domain to allow."},"example":{"domain":"help.example.org","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a30"}}}},"responses":{"201":{"description":"The allowed domain.","content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","description":"The domain name."},"organizationId":{"type":"string","format":"uuid","description":"ID of the organization that may use the domain."},"organizationName":{"type":"string","description":"Name of the organization."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the knowledge base that uses the domain."},"spaceName":{"description":"Name of the knowledge base that uses the domain.","type":["string","null"]},"createdAt":{"type":"string","format":"date-time","description":"When the domain was allowed. ISO 8601 timestamp in UTC."}},"required":["domain","organizationId","organizationName","spaceId","spaceName","createdAt"],"additionalProperties":false,"description":"A domain allowed for knowledge base portals."},"example":{"domain":"help.example.org","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a30","organizationName":"Example","spaceId":null,"spaceName":null,"createdAt":"2026-10-19T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidPortalDomain`: The domain is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidPortalDomain":{"value":{"type":"urn:lunedo:problem:invalidPortalDomain","title":"The domain is not valid","status":400,"code":"invalidPortalDomain"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`organizationNotFound`: The organization does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"organizationNotFound":{"value":{"type":"urn:lunedo:problem:organizationNotFound","title":"The organization does not exist","status":404,"code":"organizationNotFound"}}}}}},"409":{"description":"`portalDomainExists`: The domain is already allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"portalDomainExists":{"value":{"type":"urn:lunedo:problem:portalDomainExists","title":"The domain is already allowed","status":409,"code":"portalDomainExists"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/portal-domains/{domain}":{"delete":{"operationId":"portal.removeDomain","summary":"Remove a domain for portals","description":"A knowledge base that used the domain keeps its path on the instance. Readers on the domain are signed out there. The change is recorded in the audit log.\n\nRequires the permission `instance.settings.manage` on the instance.","tags":["Instance"],"x-lunedo-permission":{"action":"instance.settings.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"domain","in":"path","required":true,"description":"The domain name.","schema":{"type":"string","maxLength":253}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `portalDomainNotFound`: The domain is not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"portalDomainNotFound":{"value":{"type":"urn:lunedo:problem:portalDomainNotFound","title":"The domain is not allowed","status":404,"code":"portalDomainNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/rendering":{"get":{"operationId":"rendering.status","summary":"Get the state of PDF and Word rendering","description":"Asks the optional render container for its state and version. Without it, people still create PDF files through the print dialog of their browser; only PDF through the API and PDF of whole spaces in the background need it.\n\nRequires the permission `instance.settings.view` on the instance.","tags":["Exports"],"x-lunedo-permission":{"action":"instance.settings.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"200":{"description":"The state of rendering.","content":{"application/json":{"schema":{"type":"object","properties":{"pdf":{"type":"object","properties":{"state":{"type":"string","description":"`notConfigured` when no render container is set up, `healthy` when it answers, `unreachable` when it does not answer, refuses the token or answers something unexpected. New values can be added in later versions; handle unknown values.","x-extensible-enum":["notConfigured","healthy","unreachable"]},"reason":{"anyOf":[{"type":"string","x-extensible-enum":["connection","token","response"]},{"type":"null"}],"description":"Why the container is unreachable: no connection, a token it refuses, or an unexpected answer. New values can be added in later versions; handle unknown values."},"url":{"description":"Address of the render container, set through LUNEDO_RENDER_URL.","type":["string","null"]},"checkedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the container was asked. ISO 8601 timestamp in UTC."},"version":{"description":"Version of the render container.","type":["string","null"]},"browser":{"description":"Browser engine of the render container and its version.","type":["string","null"]},"concurrency":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Documents the container renders at the same time."},"running":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Documents being rendered now."},"waiting":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Documents waiting now."},"maxBytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Largest document with its images the container accepts."},"timeoutSeconds":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Longest time the container spends on one document."},"image":{"description":"Image of the render container that matches the version of this instance, or null when this instance does not run a release.","type":["string","null"]}},"required":["state","reason","url","checkedAt","version","browser","concurrency","running","waiting","maxBytes","timeoutSeconds","image"],"additionalProperties":false,"description":"The optional render container that creates PDF files on the server."},"word":{"type":"object","properties":{"available":{"type":"boolean","description":"Word documents are created by Lunedo itself and always available."}},"required":["available"],"additionalProperties":false,"description":"Word documents."}},"required":["pdf","word"],"additionalProperties":false,"description":"How pages become PDF and Word files."},"example":{"pdf":{"state":"healthy","reason":null,"url":"http://lunedo-render:3000","checkedAt":"2026-10-16T09:00:00.000Z","version":"1.0.2","browser":"Chromium 140.0.7339.80","concurrency":2,"running":0,"waiting":0,"maxBytes":209715200,"timeoutSeconds":300,"image":"ghcr.io/lunedo/render:1.4.2"},"word":{"available":true}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/instance/role-assignments":{"get":{"operationId":"instance.assignments","summary":"List instance role assignments","description":"Lists who holds which instance role.\n\nRequires the permission `instance.roles.view` on the instance.","tags":["Instance"],"x-lunedo-permission":{"action":"instance.roles.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"Instance role assignments.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the assignment."},"scope":{"type":"string","enum":["instance","organization"],"description":"Level of the assignment."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the organization, or null for instance assignments."},"role":{"type":"string","description":"Name of the role."},"builtInRole":{"anyOf":[{"type":"string","enum":["owner","administrator","member","securityAuditor"]},{"type":"null"}],"description":"Key of the built-in role, or null for a custom role."},"customRoleId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the custom role, or null for a built-in role."},"principalKind":{"type":"string","enum":["account","group","organizationMembers","instanceUsers"],"description":"Who receives the role."},"principalId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the account or group, or null for all members or all users."},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the assignment ends, or null. ISO 8601 timestamp in UTC."}},"required":["id","scope","organizationId","role","builtInRole","customRoleId","principalKind","principalId","expiresAt"],"additionalProperties":false,"description":"A role given to a principal."},"description":"Assignments, ordered by ID."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"One page of results."},"example":{"items":[{"id":"01929b1f-80e4-7b18-b9e5-d0c2c3adf405","scope":"instance","organizationId":null,"role":"securityAuditor","builtInRole":"securityAuditor","customRoleId":null,"principalKind":"account","principalId":"01929b1e-8d4b-7e3f-a05c-4d3e2f1a6b7c","expiresAt":null}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"instance.assign","summary":"Assign an instance role","description":"Gives an instance role to an internal account. Instance roles go to individual accounts only.\n\nRequires the permission `instance.roles.manage` on the instance.","tags":["Instance"],"x-lunedo-permission":{"action":"instance.roles.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"role":{"anyOf":[{"type":"object","properties":{"builtIn":{"type":"string","enum":["administrator","securityAuditor"],"description":"Key of the built-in instance role."}},"required":["builtIn"],"additionalProperties":false,"description":"A built-in role."},{"type":"object","properties":{"customRoleId":{"type":"string","format":"uuid","description":"ID of an instance role."}},"required":["customRoleId"],"additionalProperties":false,"description":"A custom role."}],"description":"The role to give."},"principal":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"account","description":"One account."},"id":{"type":"string","format":"uuid","description":"ID of the account."}},"required":["kind","id"],"additionalProperties":false,"description":"An internal account."},{"type":"object","properties":{"kind":{"type":"string","const":"instanceUsers","description":"Every internal user."}},"required":["kind"],"additionalProperties":false,"description":"All internal users."}],"description":"Who receives the role. All internal users are refused with `roleNeedsAccountOrGroup`: instance roles go to individual accounts only."},"expiresAt":{"description":"When the assignment ends. ISO 8601 timestamp, or null for no expiry. Leave it out to keep the default.","anyOf":[{"description":"When the assignment ends. ISO 8601 timestamp; an offset is allowed.","type":"string","format":"date-time"},{"type":"null"}]}},"required":["role","principal"],"additionalProperties":false,"description":"An instance role assignment."},"example":{"role":{"builtIn":"securityAuditor"},"principal":{"kind":"account","id":"01929b1e-8d4b-7e3f-a05c-4d3e2f1a6b7c"}}}}},"responses":{"201":{"description":"The new assignment.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the assignment."},"scope":{"type":"string","enum":["instance","organization"],"description":"Level of the assignment."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the organization, or null for instance assignments."},"role":{"type":"string","description":"Name of the role."},"builtInRole":{"anyOf":[{"type":"string","enum":["owner","administrator","member","securityAuditor"]},{"type":"null"}],"description":"Key of the built-in role, or null for a custom role."},"customRoleId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the custom role, or null for a built-in role."},"principalKind":{"type":"string","enum":["account","group","organizationMembers","instanceUsers"],"description":"Who receives the role."},"principalId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the account or group, or null for all members or all users."},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the assignment ends, or null. ISO 8601 timestamp in UTC."}},"required":["id","scope","organizationId","role","builtInRole","customRoleId","principalKind","principalId","expiresAt"],"additionalProperties":false,"description":"A role given to a principal."},"example":{"id":"01929b1f-80e4-7b18-b9e5-d0c2c3adf405","scope":"instance","organizationId":null,"role":"securityAuditor","builtInRole":"securityAuditor","customRoleId":null,"principalKind":"account","principalId":"01929b1e-8d4b-7e3f-a05c-4d3e2f1a6b7c","expiresAt":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `expiryInPast`: The expiry lies in the past. `invalidInput`: The request is not valid. `invalidPrincipal`: The role cannot go to this principal. `roleNeedsAccountOrGroup`: The role can only go to individual accounts and groups. `roleNotAssignable`: The role cannot be assigned.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"expiryInPast":{"value":{"type":"urn:lunedo:problem:expiryInPast","title":"The expiry lies in the past","status":400,"code":"expiryInPast"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidPrincipal":{"value":{"type":"urn:lunedo:problem:invalidPrincipal","title":"The role cannot go to this principal","status":400,"code":"invalidPrincipal"}},"roleNeedsAccountOrGroup":{"value":{"type":"urn:lunedo:problem:roleNeedsAccountOrGroup","title":"The role can only go to individual accounts and groups","status":400,"code":"roleNeedsAccountOrGroup"}},"roleNotAssignable":{"value":{"type":"urn:lunedo:problem:roleNotAssignable","title":"The role cannot be assigned","status":400,"code":"roleNotAssignable"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`roleNotFound`: The role does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"roleNotFound":{"value":{"type":"urn:lunedo:problem:roleNotFound","title":"The role does not exist","status":404,"code":"roleNotFound"}}}}}},"409":{"description":"`alreadyAssigned`: The role is already assigned.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"alreadyAssigned":{"value":{"type":"urn:lunedo:problem:alreadyAssigned","title":"The role is already assigned","status":409,"code":"alreadyAssigned"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/role-assignments/{assignmentId}":{"delete":{"operationId":"instance.unassign","summary":"Remove an instance role assignment","description":"Takes an instance role away. The permissions end at once.\n\nRequires the permission `instance.roles.manage` on the instance.","tags":["Instance"],"x-lunedo-permission":{"action":"instance.roles.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"assignmentId","in":"path","required":true,"description":"ID of the role assignment.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/instance/roles":{"get":{"operationId":"instance.roles","summary":"List instance roles","description":"Lists the custom roles at the instance level. Built-in roles are not listed.\n\nRequires the permission `instance.roles.view` on the instance.","tags":["Instance"],"x-lunedo-permission":{"action":"instance.roles.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"Custom instance roles.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the role."},"scope":{"type":"string","enum":["instance","organization"],"description":"Level the role applies to."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the organization, or null for instance roles."},"name":{"type":"string","description":"Name of the role, 1 to 100 characters."},"areas":{"type":"object","propertyNames":{"type":"string","description":"Area name."},"additionalProperties":{"type":"string","enum":["view","manage"],"description":"`view` reads, `manage` also changes."},"description":"Access level per area. Areas that are left out grant nothing."}},"required":["id","scope","organizationId","name","areas"],"additionalProperties":false,"description":"A role defined by an administrator."},"description":"Roles, ordered by name."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"One page of results."},"example":{"items":[{"id":"01929b1f-6fd3-7a07-a8d4-cfb1b29ce3f4","scope":"instance","organizationId":null,"name":"Operators","areas":{"operations":"manage","auditLog":"view"}}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"instance.createRole","summary":"Create an instance role","description":"Defines an instance role from areas and access levels.\n\nRequires the permission `instance.roles.manage` on the instance.","tags":["Instance"],"x-lunedo-permission":{"action":"instance.roles.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Name of the role, 1 to 100 characters, unique at the instance level."},"areas":{"type":"object","properties":{"organizations":{"description":"Access to the instance area `organizations`.","type":"string","enum":["view","manage"]},"accounts":{"description":"Access to the instance area `accounts`.","type":"string","enum":["view","manage"]},"signInAndSecurity":{"description":"Access to the instance area `signInAndSecurity`.","type":"string","enum":["view","manage"]},"settings":{"description":"Access to the instance area `settings`.","type":"string","enum":["view","manage"]},"operations":{"description":"Access to the instance area `operations`.","type":"string","enum":["view","manage"]},"auditLog":{"description":"Access to the instance area `auditLog`.","type":"string","enum":["view","manage"]}},"additionalProperties":false,"description":"Access level per instance area. Areas that are left out grant nothing."}},"required":["name","areas"],"additionalProperties":false,"description":"A new instance role. Nobody can define a role with more than they hold themselves."},"example":{"name":"Operators","areas":{"operations":"manage"}}}}},"responses":{"201":{"description":"The new role.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the role."},"scope":{"type":"string","enum":["instance","organization"],"description":"Level the role applies to."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the organization, or null for instance roles."},"name":{"type":"string","description":"Name of the role, 1 to 100 characters."},"areas":{"type":"object","propertyNames":{"type":"string","description":"Area name."},"additionalProperties":{"type":"string","enum":["view","manage"],"description":"`view` reads, `manage` also changes."},"description":"Access level per area. Areas that are left out grant nothing."}},"required":["id","scope","organizationId","name","areas"],"additionalProperties":false,"description":"A role defined by an administrator."},"example":{"id":"01929b1f-6fd3-7a07-a8d4-cfb1b29ce3f4","scope":"instance","organizationId":null,"name":"Operators","areas":{"operations":"manage","auditLog":"view"}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"409":{"description":"`roleNameTaken`: The role name is taken.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"roleNameTaken":{"value":{"type":"urn:lunedo:problem:roleNameTaken","title":"The role name is taken","status":409,"code":"roleNameTaken"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/roles/{roleId}":{"delete":{"operationId":"instance.deleteRole","summary":"Delete an instance role","description":"Deletes the role and all its assignments.\n\nRequires the permission `instance.roles.manage` on the instance.","tags":["Instance"],"x-lunedo-permission":{"action":"instance.roles.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"roleId","in":"path","required":true,"description":"ID of the instance role.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `roleNotFound`: The role does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"roleNotFound":{"value":{"type":"urn:lunedo:problem:roleNotFound","title":"The role does not exist","status":404,"code":"roleNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"patch":{"operationId":"instance.updateRole","summary":"Change an instance role","description":"Renames an instance role or changes its areas.\n\nRequires the permission `instance.roles.manage` on the instance.","tags":["Instance"],"x-lunedo-permission":{"action":"instance.roles.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"roleId","in":"path","required":true,"description":"ID of the instance role.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"New name of the role.","type":"string","minLength":1,"maxLength":100},"areas":{"description":"New access levels. Replaces all areas.","type":"object","properties":{"organizations":{"description":"Access to the instance area `organizations`.","type":"string","enum":["view","manage"]},"accounts":{"description":"Access to the instance area `accounts`.","type":"string","enum":["view","manage"]},"signInAndSecurity":{"description":"Access to the instance area `signInAndSecurity`.","type":"string","enum":["view","manage"]},"settings":{"description":"Access to the instance area `settings`.","type":"string","enum":["view","manage"]},"operations":{"description":"Access to the instance area `operations`.","type":"string","enum":["view","manage"]},"auditLog":{"description":"Access to the instance area `auditLog`.","type":"string","enum":["view","manage"]}},"additionalProperties":false}},"additionalProperties":false,"description":"Fields to change."},"example":{"areas":{"operations":"view"}}}}},"responses":{"200":{"description":"The changed role.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the role."},"scope":{"type":"string","enum":["instance","organization"],"description":"Level the role applies to."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the organization, or null for instance roles."},"name":{"type":"string","description":"Name of the role, 1 to 100 characters."},"areas":{"type":"object","propertyNames":{"type":"string","description":"Area name."},"additionalProperties":{"type":"string","enum":["view","manage"],"description":"`view` reads, `manage` also changes."},"description":"Access level per area. Areas that are left out grant nothing."}},"required":["id","scope","organizationId","name","areas"],"additionalProperties":false,"description":"A role defined by an administrator."},"example":{"id":"01929b1f-6fd3-7a07-a8d4-cfb1b29ce3f4","scope":"instance","organizationId":null,"name":"Operators","areas":{"operations":"manage","auditLog":"view"}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `roleNotFound`: The role does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"roleNotFound":{"value":{"type":"urn:lunedo:problem:roleNotFound","title":"The role does not exist","status":404,"code":"roleNotFound"}}}}}},"409":{"description":"`roleNameTaken`: The role name is taken.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"roleNameTaken":{"value":{"type":"urn:lunedo:problem:roleNameTaken","title":"The role name is taken","status":409,"code":"roleNameTaken"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/settings":{"get":{"operationId":"instance.settings","summary":"List instance settings","description":"Lists the settings at the instance level with their effective values.\n\nRequires the permission `instance.settings.view` on the instance.","tags":["Instance"],"x-lunedo-permission":{"action":"instance.settings.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"Instance settings.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the setting."},"value":{"description":"Effective value at this level.","$ref":"#/components/schemas/Schema113ae44d8375"},"defaultValue":{"description":"Value that applies when no level sets one.","$ref":"#/components/schemas/Schemafbc378f59d82"},"source":{"type":"string","description":"Level the effective value comes from, or `default`."},"lockedBy":{"description":"Higher level that locked the setting, or null.","type":["string","null"]},"locked":{"type":"boolean","description":"Whether this level locks the setting for lower levels."},"lockable":{"type":"boolean","description":"Whether the setting can be locked."},"levelsBelow":{"type":"array","items":{"type":"string"},"description":"Lower levels where the setting can be set. A lock at this level applies to them."},"editable":{"type":"boolean","description":"Whether the setting can be changed through the settings endpoint."},"stricterOnly":{"anyOf":[{"type":"string","enum":["lower","higher"]},{"type":"null"}],"description":"For a limit: `lower` when lower levels may only choose a lower value, `higher` when only a higher one, null otherwise. The value inherited from above is the bound."},"maximum":{"description":"Highest value allowed, set for the instance, or null when the setting has no maximum. `unlimited` allows any value.","$ref":"#/components/schemas/Schema682d67ac39ef"},"minimum":{"description":"Lowest value allowed, set for the instance, or null when the setting has no minimum.","type":["number","null"]},"levels":{"type":"array","items":{"type":"object","properties":{"level":{"type":"string","description":"The level: `instance`, `organization`, `space` or `user`."},"value":{"description":"Value stored at this level, or null.","$ref":"#/components/schemas/Schema1a810d563c56"},"locked":{"type":"boolean","description":"Whether this level locks the setting."},"effective":{"type":"boolean","description":"False when a lock above or a stricter value above makes this level's value ineffective."}},"required":["level","value","locked","effective"],"additionalProperties":false,"description":"The state of the setting at one level."},"description":"Every level the setting applies to, from the instance down to this level."}},"required":["key","value","defaultValue","source","lockedBy","locked","lockable","levelsBelow","editable","stricterOnly","maximum","minimum","levels"],"additionalProperties":false,"description":"A setting with its effective value and where it comes from."},"description":"Settings, ordered by key."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"One page of results."},"example":{"items":[{"key":"auth.passwordMinLength","value":14,"defaultValue":12,"source":"instance","lockedBy":null,"locked":false,"lockable":true,"levelsBelow":["organization"],"editable":true,"stricterOnly":"higher","maximum":null,"minimum":null,"levels":[{"level":"instance","value":14,"locked":false,"effective":true},{"level":"organization","value":null,"locked":false,"effective":true}]}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/instance/settings/{key}":{"put":{"operationId":"instance.updateSetting","summary":"Change an instance setting","description":"Sets, clears or locks an instance setting. Each setting needs the manage level of its area: sign-in, audit log, organizations or settings.\n\nRequires one of the permissions `instance.settings.manage`, `instance.signIn.manage`, `instance.audit.manage`, `instance.organizations.manage` on the instance; the request decides which.","tags":["Instance"],"x-lunedo-permission":{"action":"instance.settings.manage","alternatives":["instance.signIn.manage","instance.audit.manage","instance.organizations.manage"],"resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"key","in":"path","required":true,"description":"Key of the setting.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"value":{"description":"New value. Its type depends on the setting.","$ref":"#/components/schemas/Schema113ae44d8375"},"clear":{"description":"Remove the value at this level, so the level above applies.","type":"boolean","const":true},"locked":{"description":"Lock or unlock the setting for the levels below.","type":"boolean"}},"additionalProperties":false,"description":"A change to a setting. Send at least one field."},"example":{"value":30,"locked":true}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidSetting`: The setting value is not valid. `settingAboveMaximum`: The value is above the maximum set for the instance. `settingManagedElsewhere`: The setting is changed through another endpoint.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidSetting":{"value":{"type":"urn:lunedo:problem:invalidSetting","title":"The setting value is not valid","status":400,"code":"invalidSetting"}},"settingAboveMaximum":{"value":{"type":"urn:lunedo:problem:settingAboveMaximum","title":"The value is above the maximum set for the instance","status":400,"code":"settingAboveMaximum"}},"settingManagedElsewhere":{"value":{"type":"urn:lunedo:problem:settingManagedElsewhere","title":"The setting is changed through another endpoint","status":400,"code":"settingManagedElsewhere"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`settingNotAtLevel`: The setting cannot be set at this level.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"settingNotAtLevel":{"value":{"type":"urn:lunedo:problem:settingNotAtLevel","title":"The setting cannot be set at this level","status":409,"code":"settingNotAtLevel"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/storage":{"get":{"operationId":"storage.status","summary":"Get the usage of the file store","description":"Shows the usage of the file store, the active warning level and the settings of the warnings. For a local volume the usage is read from the volume; for S3 storage it is the running total of the files Lunedo stores, measured against the limit if one is set.\n\nRequires the permission `instance.settings.view` on the instance.","tags":["Storage"],"x-lunedo-permission":{"action":"instance.settings.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"200":{"description":"Usage and settings.","content":{"application/json":{"schema":{"type":"object","properties":{"store":{"type":"string","enum":["local","s3"],"description":"Where files are stored: a local volume or S3-compatible storage."},"measured":{"type":"boolean","description":"Whether Lunedo can measure the usage. False for S3 storage without a limit."},"inactiveReason":{"anyOf":[{"type":"string","enum":["noLimit"]},{"type":"null"}],"description":"Why warnings are inactive, or null. `noLimit`: S3 does not report free space, so a limit is needed."},"usedBytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Bytes in use on the volume, or stored in S3. Null when not measured."},"totalBytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size of the volume, or the S3 limit. Null when not measured."},"percent":{"description":"Usage in percent of the size or limit. Null when not measured.","type":["number","null"]},"level":{"type":"integer","minimum":0,"maximum":3,"description":"The active level: 0 normal, 1 warning, 2 large exports and imports are refused, 3 uploads are refused too."},"thresholds":{"type":"object","properties":{"warning":{"type":"integer","minimum":1,"maximum":100,"description":"Usage in percent where the warning level starts."},"largeWrites":{"type":"integer","minimum":1,"maximum":100,"description":"Usage in percent where new exports and imports are refused."},"critical":{"type":"integer","minimum":1,"maximum":100,"description":"Usage in percent where uploads are refused too."}},"required":["warning","largeWrites","critical"],"additionalProperties":false,"description":"The three levels in percent of usage, in ascending order."},"s3LimitBytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The limit for S3 storage in bytes, or null for none."},"reminder":{"type":"string","enum":["off","daily","weekly","monthly"],"description":"How often an active level is announced again: `off`, `daily`, `weekly` or `monthly`."},"operationsEmails":{"type":"array","items":{"type":"string"},"description":"E-mail addresses of the operations contacts, for example an IT ticket address."},"teamsWebhook":{"type":"object","properties":{"configured":{"type":"boolean","description":"Whether a Teams Workflows webhook is set."},"host":{"description":"Host name of the webhook. The full address is never returned.","type":["string","null"]}},"required":["configured","host"],"additionalProperties":false,"description":"The optional Microsoft Teams webhook of the operations contacts."},"checkedAt":{"description":"When the usage was last checked. ISO 8601 timestamp in UTC.","type":["string","null"]}},"required":["store","measured","inactiveReason","usedBytes","totalBytes","percent","level","thresholds","s3LimitBytes","reminder","operationsEmails","teamsWebhook","checkedAt"],"additionalProperties":false,"description":"Usage and settings of the file store warnings."},"example":{"store":"local","measured":true,"inactiveReason":null,"usedBytes":412000000000,"totalBytes":500000000000,"percent":82.4,"level":1,"thresholds":{"warning":80,"largeWrites":90,"critical":95},"s3LimitBytes":null,"reminder":"weekly","operationsEmails":["it-tickets@example.org"],"teamsWebhook":{"configured":true,"host":"prod-12.westeurope.logic.azure.com"},"checkedAt":"2026-10-15T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"put":{"operationId":"storage.configure","summary":"Change the storage warnings","description":"Changes the three levels, the S3 limit, the reminder interval and the operations contacts. The levels must stay in ascending order. The Teams webhook address is stored encrypted and never returned. Changing the operations contacts is audited.\n\nRequires the permission `instance.settings.manage` on the instance.","tags":["Storage"],"x-lunedo-permission":{"action":"instance.settings.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"thresholds":{"description":"The levels to change. The result must stay in ascending order: warning, large writes, critical.","type":"object","properties":{"warning":{"description":"Usage in percent where the warning level starts.","type":"integer","minimum":1,"maximum":100},"largeWrites":{"description":"Usage in percent where new exports and imports are refused.","type":"integer","minimum":1,"maximum":100},"critical":{"description":"Usage in percent where uploads are refused too.","type":"integer","minimum":1,"maximum":100}},"additionalProperties":false},"s3LimitBytes":{"description":"The limit for S3 storage in bytes, or null to remove it.","anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}]},"reminder":{"description":"How often an active level is announced again.","type":"string","enum":["off","daily","weekly","monthly"]},"operationsEmails":{"description":"All e-mail addresses of the operations contacts, up to 20. Replaces the earlier list.","maxItems":20,"type":"array","items":{"type":"string","maxLength":254}},"teamsWebhook":{"description":"The Teams Workflows webhook address, or null to remove it. Leave it out to keep it.","anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]}},"additionalProperties":false,"description":"Changes to the storage warnings. Leave out what stays as it is."},"example":{"thresholds":{"warning":75,"largeWrites":88,"critical":94},"reminder":"weekly"}}}},"responses":{"200":{"description":"Usage and settings.","content":{"application/json":{"schema":{"type":"object","properties":{"store":{"type":"string","enum":["local","s3"],"description":"Where files are stored: a local volume or S3-compatible storage."},"measured":{"type":"boolean","description":"Whether Lunedo can measure the usage. False for S3 storage without a limit."},"inactiveReason":{"anyOf":[{"type":"string","enum":["noLimit"]},{"type":"null"}],"description":"Why warnings are inactive, or null. `noLimit`: S3 does not report free space, so a limit is needed."},"usedBytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Bytes in use on the volume, or stored in S3. Null when not measured."},"totalBytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size of the volume, or the S3 limit. Null when not measured."},"percent":{"description":"Usage in percent of the size or limit. Null when not measured.","type":["number","null"]},"level":{"type":"integer","minimum":0,"maximum":3,"description":"The active level: 0 normal, 1 warning, 2 large exports and imports are refused, 3 uploads are refused too."},"thresholds":{"type":"object","properties":{"warning":{"type":"integer","minimum":1,"maximum":100,"description":"Usage in percent where the warning level starts."},"largeWrites":{"type":"integer","minimum":1,"maximum":100,"description":"Usage in percent where new exports and imports are refused."},"critical":{"type":"integer","minimum":1,"maximum":100,"description":"Usage in percent where uploads are refused too."}},"required":["warning","largeWrites","critical"],"additionalProperties":false,"description":"The three levels in percent of usage, in ascending order."},"s3LimitBytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The limit for S3 storage in bytes, or null for none."},"reminder":{"type":"string","enum":["off","daily","weekly","monthly"],"description":"How often an active level is announced again: `off`, `daily`, `weekly` or `monthly`."},"operationsEmails":{"type":"array","items":{"type":"string"},"description":"E-mail addresses of the operations contacts, for example an IT ticket address."},"teamsWebhook":{"type":"object","properties":{"configured":{"type":"boolean","description":"Whether a Teams Workflows webhook is set."},"host":{"description":"Host name of the webhook. The full address is never returned.","type":["string","null"]}},"required":["configured","host"],"additionalProperties":false,"description":"The optional Microsoft Teams webhook of the operations contacts."},"checkedAt":{"description":"When the usage was last checked. ISO 8601 timestamp in UTC.","type":["string","null"]}},"required":["store","measured","inactiveReason","usedBytes","totalBytes","percent","level","thresholds","s3LimitBytes","reminder","operationsEmails","teamsWebhook","checkedAt"],"additionalProperties":false,"description":"Usage and settings of the file store warnings."},"example":{"store":"local","measured":true,"inactiveReason":null,"usedBytes":412000000000,"totalBytes":500000000000,"percent":82.4,"level":1,"thresholds":{"warning":80,"largeWrites":90,"critical":95},"s3LimitBytes":null,"reminder":"weekly","operationsEmails":["it-tickets@example.org"],"teamsWebhook":{"configured":true,"host":"prod-12.westeurope.logic.azure.com"},"checkedAt":"2026-10-15T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidStorageSettings`: The storage settings are not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidStorageSettings":{"value":{"type":"urn:lunedo:problem:invalidStorageSettings","title":"The storage settings are not valid","status":400,"code":"invalidStorageSettings"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/storage/test":{"post":{"operationId":"storage.test","summary":"Send a test message to the operations contacts","description":"Sends a short test message to the operations e-mail addresses and the Teams webhook, so that you can check that warnings arrive.\n\nRequires the permission `instance.settings.manage` on the instance.","tags":["Storage"],"x-lunedo-permission":{"action":"instance.settings.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"200":{"description":"What was sent.","content":{"application/json":{"schema":{"type":"object","properties":{"addresses":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many e-mail addresses were sent a test message."},"teams":{"anyOf":[{"type":"object","properties":{"delivered":{"type":"boolean","description":"Whether Teams accepted the message."},"reason":{"description":"Why Teams did not accept it, or null.","type":["string","null"]},"status":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"HTTP status of Teams, or null."}},"required":["delivered","reason","status"],"additionalProperties":false},{"type":"null"}],"description":"The result for the Teams webhook, or null when none is set."}},"required":["addresses","teams"],"additionalProperties":false,"description":"The result of the test message to the operations contacts."},"example":{"addresses":1,"teams":{"delivered":true,"reason":null,"status":null}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/template-imports":{"post":{"operationId":"templateFiles.instanceImport","summary":"Upload a template file for import into the instance","description":"Checks a template file and returns a preview, like for spaces; nothing is saved yet.\n\nRequires the permission `instance.templates.manage` on the instance.","tags":["Templates"],"x-lunedo-permission":{"action":"instance.templates.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"name","in":"query","required":true,"description":"Name of the uploaded file. Paths and control characters are removed.","schema":{"type":"string","minLength":1,"maxLength":1020}}],"requestBody":{"required":true,"description":"The template file.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"201":{"description":"The preview.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the preview; confirm or discard it with this ID."},"fileName":{"type":"string","description":"Name of the uploaded file."},"templates":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Position in the file, counted from 0."},"name":{"type":"string","description":"Name of the template, or `#n` when the file gives none."},"description":{"type":"string","description":"Short description."},"category":{"anyOf":[{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"]},{"type":"null"}],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"language":{"anyOf":[{"type":"string","enum":["en","de"]},{"type":"null"}],"description":"Language the file states, or null."},"title":{"type":"string","description":"Title pattern of new pages."},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Input fields."},"series":{"anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","description":"How often. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"Weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"Default rhythm."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Default duration in minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false,"description":"Defaults of a series template."},{"type":"null"}],"description":"Series defaults, or null."},"document":{"anyOf":[{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},{"type":"null"}],"description":"Content as it will be saved, or null if it is not valid."},"files":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the file; the preview content refers to it."},"name":{"type":"string","description":"File name."},"mediaType":{"type":"string","description":"Media type."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size in bytes after the safety checks."}},"required":["id","name","mediaType","size"],"additionalProperties":false,"description":"A file of the template."},"description":"Files the content uses."},"removed":{"type":"object","propertyNames":{"type":"string","enum":["pageLink","mention","include","diagramReference","whiteboard","templateButton","report","roadmap","person","comment","meetingTopic","file","unsupportedMacro"]},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"What is removed because it cannot work in another instance, by kind: `pageLink` (links to pages and spaces), `mention`, `include`, `diagramReference`, `whiteboard`, `templateButton`, `report`, `roadmap`, `person`, `comment`, `meetingTopic`, `file` (files that are not part of the template or not images) and `unsupportedMacro`."},"blockedEmbeds":{"type":"array","items":{"type":"string","description":"Address of an embed."},"description":"Embeds this instance does not allow; they stay in the content and show as links."},"problems":{"type":"array","items":{"type":"object","properties":{"place":{"description":"Where, such as `field 3` or `content`.","type":["string","null"]},"message":{"type":"string","description":"Explanation naming the template and the place."}},"required":["place","message"],"additionalProperties":false,"description":"A problem."},"description":"Why the template cannot be imported; empty when it can."},"valid":{"type":"boolean","description":"Whether the template can be imported."},"conflict":{"anyOf":[{"type":"object","properties":{"templateId":{"type":"string","format":"uuid","description":"The template with the same name at this level."},"suggestedName":{"type":"string","description":"A new name to use instead, in the caller's language."}},"required":["templateId","suggestedName"],"additionalProperties":false},{"type":"null"}],"description":"A template with the same name at this level, or null."}},"required":["index","name","description","category","language","title","fields","series","document","files","removed","blockedEmbeds","problems","valid","conflict"],"additionalProperties":false,"description":"A template of the uploaded file."},"description":"The templates of the file."},"expiresAt":{"type":"string","format":"date-time","description":"When the preview is discarded."}},"required":["id","fileName","templates","expiresAt"],"additionalProperties":false,"description":"What an import will create. Nothing is saved before it is confirmed."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5aa0","fileName":"change-request.lunedo-template.zip","templates":[{"index":0,"name":"Change request","description":"Planned change with risk and rollback","category":"operations","language":"en","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"series":null,"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"files":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a91","name":"rollout.png","mediaType":"image/png","size":48213}],"removed":{},"blockedEmbeds":[],"problems":[],"valid":true,"conflict":{"templateId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","suggestedName":"Change request (imported)"}}],"expiresAt":"2026-10-18T20:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidTemplateFile`: The file is not a valid Lunedo template file. `nestedTemplateArchive`: The archive contains another archive. `newerTemplateFormat`: The template file was written by a newer Lunedo. `templateArchiveCompression`: A file in the archive is compressed too strongly. `tooManyTemplateFiles`: The archive holds more files than allowed. `tooManyTemplates`: The file holds more templates than allowed. `unexpectedTemplateEntry`: The archive contains an unexpected file. `unsafeTemplateArchive`: The archive contains unsafe entries.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidTemplateFile":{"value":{"type":"urn:lunedo:problem:invalidTemplateFile","title":"The file is not a valid Lunedo template file","status":400,"code":"invalidTemplateFile"}},"nestedTemplateArchive":{"value":{"type":"urn:lunedo:problem:nestedTemplateArchive","title":"The archive contains another archive","status":400,"code":"nestedTemplateArchive"}},"newerTemplateFormat":{"value":{"type":"urn:lunedo:problem:newerTemplateFormat","title":"The template file was written by a newer Lunedo","status":400,"code":"newerTemplateFormat"}},"templateArchiveCompression":{"value":{"type":"urn:lunedo:problem:templateArchiveCompression","title":"A file in the archive is compressed too strongly","status":400,"code":"templateArchiveCompression"}},"tooManyTemplateFiles":{"value":{"type":"urn:lunedo:problem:tooManyTemplateFiles","title":"The archive holds more files than allowed","status":400,"code":"tooManyTemplateFiles"}},"tooManyTemplates":{"value":{"type":"urn:lunedo:problem:tooManyTemplates","title":"The file holds more templates than allowed","status":400,"code":"tooManyTemplates"}},"unexpectedTemplateEntry":{"value":{"type":"urn:lunedo:problem:unexpectedTemplateEntry","title":"The archive contains an unexpected file","status":400,"code":"unexpectedTemplateEntry"}},"unsafeTemplateArchive":{"value":{"type":"urn:lunedo:problem:unsafeTemplateArchive","title":"The archive contains unsafe entries","status":400,"code":"unsafeTemplateArchive"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"408":{"description":"`uploadTimeout`: The upload took too long.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"uploadTimeout":{"value":{"type":"urn:lunedo:problem:uploadTimeout","title":"The upload took too long","status":408,"code":"uploadTimeout"}}}}}},"413":{"description":"`fileTooLarge`: The file is larger than allowed. `templateArchiveTooLarge`: The archive unpacks to more than allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"fileTooLarge":{"value":{"type":"urn:lunedo:problem:fileTooLarge","title":"The file is larger than allowed","status":413,"code":"fileTooLarge"}},"templateArchiveTooLarge":{"value":{"type":"urn:lunedo:problem:templateArchiveTooLarge","title":"The archive unpacks to more than allowed","status":413,"code":"templateArchiveTooLarge"}}}}}},"415":{"description":"`unsupportedMediaType`: The request body has an unsupported type.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unsupportedMediaType":{"value":{"type":"urn:lunedo:problem:unsupportedMediaType","title":"The request body has an unsupported type","status":415,"code":"unsupportedMediaType"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`busy`: The server is busy. `maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"busy":{"value":{"type":"urn:lunedo:problem:busy","title":"The server is busy","status":503,"code":"busy"}},"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}},"507":{"description":"`storageFull`: Storage is almost full.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"storageFull":{"value":{"type":"urn:lunedo:problem:storageFull","title":"Storage is almost full","status":507,"code":"storageFull"}}}}}}}}},"/api/v1/instance/template-imports/{importId}":{"delete":{"operationId":"templateFiles.instanceDiscard","summary":"Discard an instance import preview","description":"Discards your preview and its files.\n\nRequires the permission `instance.templates.manage` on the instance.","tags":["Templates"],"x-lunedo-permission":{"action":"instance.templates.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import preview.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `templateImportNotFound`: The import preview does not exist anymore.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"templateImportNotFound":{"value":{"type":"urn:lunedo:problem:templateImportNotFound","title":"The import preview does not exist anymore","status":404,"code":"templateImportNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/template-imports/{importId}/confirm":{"post":{"operationId":"templateFiles.instanceConfirm","summary":"Confirm an import into the instance","description":"Imports the templates of your preview as instance templates, with the same decisions as for spaces.\n\nRequires the permission `instance.templates.manage` on the instance.","tags":["Templates"],"x-lunedo-permission":{"action":"instance.templates.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import preview.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"decisions":{"default":[],"description":"Decisions per template. Templates without a decision are created under their own name.","maxItems":50,"type":"array","items":{"type":"object","properties":{"index":{"type":"integer","minimum":0,"maximum":50,"description":"Position in the file."},"action":{"type":"string","enum":["create","replace","skip"],"description":"`create` a new template, `replace` the template with the same name (it keeps its ID), or `skip` it."},"name":{"description":"Name of a new template; default: the name in the file.","type":"string","maxLength":200}},"required":["index","action"],"additionalProperties":false,"description":"What to do with one template."}},"skipInvalid":{"default":false,"description":"Import the valid templates when others in the file are not valid. Without it, nothing is imported.","type":"boolean"}},"additionalProperties":false,"description":"Confirms an import preview."},"example":{"decisions":[],"skipInvalid":true}}}},"responses":{"200":{"description":"The result.","content":{"application/json":{"schema":{"type":"object","properties":{"created":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"ID of the template. Built-in templates have IDs starting with `builtin:`."},"level":{"type":"string","enum":["builtIn","instance","organization","space"],"description":"Where the template comes from: built in, or from the instance, the organization or the space."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization of an organization template, or null."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space of a space template, or null."},"name":{"type":"string","description":"Name."},"description":{"type":"string","description":"Short description."},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","description":"Title of new pages; `{key}` inserts the value of an input field."},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","description":"How often. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"Weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"Default rhythm."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Default duration in minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false,"description":"Defaults of a series template."},{"type":"null"}],"description":"For a series template: defaults for rhythm and duration of new meeting series; otherwise null."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Article type of articles created from a template of a knowledge base, or null."},"updatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the template last changed, or null for built-in templates. ISO 8601 timestamp in UTC."}},"required":["id","level","organizationId","spaceId","name","description","category","title","fields","document","series","articleType","updatedAt"],"additionalProperties":false,"description":"A page template."},"description":"Templates created."},"replaced":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"ID of the template. Built-in templates have IDs starting with `builtin:`."},"level":{"type":"string","enum":["builtIn","instance","organization","space"],"description":"Where the template comes from: built in, or from the instance, the organization or the space."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization of an organization template, or null."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space of a space template, or null."},"name":{"type":"string","description":"Name."},"description":{"type":"string","description":"Short description."},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","description":"Title of new pages; `{key}` inserts the value of an input field."},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","description":"How often. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"Weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"Default rhythm."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Default duration in minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false,"description":"Defaults of a series template."},{"type":"null"}],"description":"For a series template: defaults for rhythm and duration of new meeting series; otherwise null."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Article type of articles created from a template of a knowledge base, or null."},"updatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the template last changed, or null for built-in templates. ISO 8601 timestamp in UTC."}},"required":["id","level","organizationId","spaceId","name","description","category","title","fields","document","series","articleType","updatedAt"],"additionalProperties":false,"description":"A page template."},"description":"Templates replaced; they keep their IDs."},"skipped":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Templates not imported."}},"required":["created","replaced","skipped"],"additionalProperties":false,"description":"The result of an import."},"example":{"created":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","level":"space","organizationId":null,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","name":"Change request","description":"Planned change with risk and rollback","category":"operations","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"series":null,"articleType":null,"updatedAt":"2026-10-05T08:00:00.000Z"}],"replaced":[],"skipped":1}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidTemplateName`: The template name is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidTemplateName":{"value":{"type":"urn:lunedo:problem:invalidTemplateName","title":"The template name is not valid","status":400,"code":"invalidTemplateName"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `templateImportNotFound`: The import preview does not exist anymore. `templateNotFound`: The template does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"templateImportNotFound":{"value":{"type":"urn:lunedo:problem:templateImportNotFound","title":"The import preview does not exist anymore","status":404,"code":"templateImportNotFound"}},"templateNotFound":{"value":{"type":"urn:lunedo:problem:templateNotFound","title":"The template does not exist","status":404,"code":"templateNotFound"}}}}}},"409":{"description":"`invalidTemplatesInFile`: Some templates in the file are not valid. `templateNameTaken`: A template with this name exists already.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidTemplatesInFile":{"value":{"type":"urn:lunedo:problem:invalidTemplatesInFile","title":"Some templates in the file are not valid","status":409,"code":"invalidTemplatesInFile"}},"templateNameTaken":{"value":{"type":"urn:lunedo:problem:templateNameTaken","title":"A template with this name exists already","status":409,"code":"templateNameTaken"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}},"507":{"description":"`storageFull`: Storage is almost full.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"storageFull":{"value":{"type":"urn:lunedo:problem:storageFull","title":"Storage is almost full","status":507,"code":"storageFull"}}}}}}}}},"/api/v1/instance/template-imports/{importId}/files/{fileId}/content":{"get":{"operationId":"templateFiles.instanceImportFile","summary":"Download a file of an instance import preview","description":"Sends a checked file of your import preview.\n\nRequires the permission `instance.templates.manage` on the instance.","tags":["Templates"],"x-lunedo-permission":{"action":"instance.templates.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"importId","in":"path","required":true,"description":"ID of the import preview.","schema":{"type":"string","format":"uuid"}},{"name":"fileId","in":"path","required":true,"description":"ID of the file.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The file. Sent with `Content-Security-Policy: sandbox` and `X-Content-Type-Options: nosniff`; ranges are supported.","content":{"image/png":{"schema":{"type":"string"},"example":""},"image/jpeg":{"schema":{"type":"string"},"example":""},"image/gif":{"schema":{"type":"string"},"example":""},"image/webp":{"schema":{"type":"string"},"example":""},"image/svg+xml":{"schema":{"type":"string"},"example":""},"*/*":{"schema":{"type":"string"},"example":""}}},"206":{"description":"Part of the file, for a request with a `Range` header.","content":{"image/png":{"schema":{"type":"string"},"example":""},"image/jpeg":{"schema":{"type":"string"},"example":""},"image/gif":{"schema":{"type":"string"},"example":""},"image/webp":{"schema":{"type":"string"},"example":""},"image/svg+xml":{"schema":{"type":"string"},"example":""},"*/*":{"schema":{"type":"string"},"example":""}}},"304":{"description":"Not modified: the file matches the `If-None-Match` header."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `templateImportNotFound`: The import preview does not exist anymore.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"templateImportNotFound":{"value":{"type":"urn:lunedo:problem:templateImportNotFound","title":"The import preview does not exist anymore","status":404,"code":"templateImportNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/instance/templates":{"get":{"operationId":"templates.instanceTemplates","summary":"List the templates of the instance","description":"Lists the templates available in all organizations. Built-in templates are not part of this list.\n\nRequires the permission `instance.templates.manage` on the instance.","tags":["Templates"],"x-lunedo-permission":{"action":"instance.templates.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"200":{"description":"Templates.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"ID of the template. Built-in templates have IDs starting with `builtin:`."},"level":{"type":"string","enum":["builtIn","instance","organization","space"],"description":"Where the template comes from: built in, or from the instance, the organization or the space."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization of an organization template, or null."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space of a space template, or null."},"name":{"type":"string","description":"Name."},"description":{"type":"string","description":"Short description."},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","description":"Title of new pages; `{key}` inserts the value of an input field."},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","description":"How often. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"Weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"Default rhythm."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Default duration in minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false,"description":"Defaults of a series template."},{"type":"null"}],"description":"For a series template: defaults for rhythm and duration of new meeting series; otherwise null."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Article type of articles created from a template of a knowledge base, or null."},"updatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the template last changed, or null for built-in templates. ISO 8601 timestamp in UTC."}},"required":["id","level","organizationId","spaceId","name","description","category","title","fields","document","series","articleType","updatedAt"],"additionalProperties":false,"description":"A page template."},"description":"Templates."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","level":"instance","organizationId":null,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","name":"Change request","description":"Planned change with risk and rollback","category":"operations","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"series":null,"articleType":null,"updatedAt":"2026-10-05T08:00:00.000Z"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"templates.createInstanceTemplate","summary":"Create an instance template","description":"Creates a template for all organizations.\n\nRequires the permission `instance.templates.manage` on the instance.","tags":["Templates"],"x-lunedo-permission":{"action":"instance.templates.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"description":"Name, 1 to 100 characters."},"description":{"default":"","description":"Short description, up to 300 characters.","type":"string","maxLength":300},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","maxLength":255,"description":"Title of new pages, 1 to 255 characters."},"fields":{"maxItems":20,"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Up to 20 input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"description":"Makes the template a series template with these defaults; null or left out for a page template.","anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","enum":["none","daily","weekly","monthly","yearly"],"description":"`none` for no fixed rhythm, otherwise how often the meetings repeat."},"interval":{"default":1,"description":"Every how many days, weeks, months or years. 2 weekly is every two weeks, 3 monthly is quarterly.","type":"integer","minimum":1,"maximum":52},"weekdays":{"description":"For `weekly`: the weekdays of the meetings, at least one.","maxItems":7,"type":"array","items":{"type":"string","enum":["MO","TU","WE","TH","FR","SA","SU"],"description":"Weekday as in iCalendar: `MO` to `SU`."}},"monthDay":{"description":"For `monthly` by date: the day of the month.","type":"integer","minimum":1,"maximum":31},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"For `monthly` by weekday: the weekday, for example `TU`.","type":"string","enum":["MO","TU","WE","TH","FR","SA","SU"]}},"required":["frequency"],"additionalProperties":false,"description":"The rhythm of a series, as the interface offers it."},"durationMinutes":{"type":"integer","minimum":5,"maximum":1440,"description":"Minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false},{"type":"null"}]},"articleType":{"description":"Article type of articles created from the template. Only templates of a knowledge base have one; left out, a change keeps the current type.","anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}]}},"required":["name","category","title","fields","document"],"additionalProperties":false,"description":"A template."},"example":{"name":"Change request","description":"Planned change with risk and rollback","category":"operations","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]}}}}},"responses":{"201":{"description":"The template.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"ID of the template. Built-in templates have IDs starting with `builtin:`."},"level":{"type":"string","enum":["builtIn","instance","organization","space"],"description":"Where the template comes from: built in, or from the instance, the organization or the space."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization of an organization template, or null."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space of a space template, or null."},"name":{"type":"string","description":"Name."},"description":{"type":"string","description":"Short description."},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","description":"Title of new pages; `{key}` inserts the value of an input field."},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","description":"How often. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"Weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"Default rhythm."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Default duration in minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false,"description":"Defaults of a series template."},{"type":"null"}],"description":"For a series template: defaults for rhythm and duration of new meeting series; otherwise null."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Article type of articles created from a template of a knowledge base, or null."},"updatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the template last changed, or null for built-in templates. ISO 8601 timestamp in UTC."}},"required":["id","level","organizationId","spaceId","name","description","category","title","fields","document","series","articleType","updatedAt"],"additionalProperties":false,"description":"A page template."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","level":"instance","organizationId":null,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","name":"Change request","description":"Planned change with risk and rollback","category":"operations","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"series":null,"articleType":null,"updatedAt":"2026-10-05T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidDescription`: The description is too long. `invalidDocument`: The document does not match the editor schema. `invalidInput`: The request is not valid. `invalidTemplateFields`: The input fields of the template are not valid. `invalidTemplateName`: The template name is not valid. `invalidTitle`: The title is not valid. `unknownTemplateField`: The template uses an input field that does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidDescription":{"value":{"type":"urn:lunedo:problem:invalidDescription","title":"The description is too long","status":400,"code":"invalidDescription"}},"invalidDocument":{"value":{"type":"urn:lunedo:problem:invalidDocument","title":"The document does not match the editor schema","status":400,"code":"invalidDocument"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidTemplateFields":{"value":{"type":"urn:lunedo:problem:invalidTemplateFields","title":"The input fields of the template are not valid","status":400,"code":"invalidTemplateFields"}},"invalidTemplateName":{"value":{"type":"urn:lunedo:problem:invalidTemplateName","title":"The template name is not valid","status":400,"code":"invalidTemplateName"}},"invalidTitle":{"value":{"type":"urn:lunedo:problem:invalidTitle","title":"The title is not valid","status":400,"code":"invalidTitle"}},"unknownTemplateField":{"value":{"type":"urn:lunedo:problem:unknownTemplateField","title":"The template uses an input field that does not exist","status":400,"code":"unknownTemplateField"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/templates/{templateId}":{"delete":{"operationId":"templates.deleteInstanceTemplate","summary":"Delete an instance template","description":"Deletes a template of the instance. Pages created from it stay.\n\nRequires the permission `instance.templates.manage` on the instance.","tags":["Templates"],"x-lunedo-permission":{"action":"instance.templates.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"templateId","in":"path","required":true,"description":"ID of the template.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"put":{"operationId":"templates.updateInstanceTemplate","summary":"Change an instance template","description":"Changes a template of the instance. Pages created from it before stay as they are.\n\nRequires the permission `instance.templates.manage` on the instance.","tags":["Templates"],"x-lunedo-permission":{"action":"instance.templates.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"templateId","in":"path","required":true,"description":"ID of the template.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"description":"Name, 1 to 100 characters."},"description":{"default":"","description":"Short description, up to 300 characters.","type":"string","maxLength":300},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","maxLength":255,"description":"Title of new pages, 1 to 255 characters."},"fields":{"maxItems":20,"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Up to 20 input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"description":"Makes the template a series template with these defaults; null or left out for a page template.","anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","enum":["none","daily","weekly","monthly","yearly"],"description":"`none` for no fixed rhythm, otherwise how often the meetings repeat."},"interval":{"default":1,"description":"Every how many days, weeks, months or years. 2 weekly is every two weeks, 3 monthly is quarterly.","type":"integer","minimum":1,"maximum":52},"weekdays":{"description":"For `weekly`: the weekdays of the meetings, at least one.","maxItems":7,"type":"array","items":{"type":"string","enum":["MO","TU","WE","TH","FR","SA","SU"],"description":"Weekday as in iCalendar: `MO` to `SU`."}},"monthDay":{"description":"For `monthly` by date: the day of the month.","type":"integer","minimum":1,"maximum":31},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"For `monthly` by weekday: the weekday, for example `TU`.","type":"string","enum":["MO","TU","WE","TH","FR","SA","SU"]}},"required":["frequency"],"additionalProperties":false,"description":"The rhythm of a series, as the interface offers it."},"durationMinutes":{"type":"integer","minimum":5,"maximum":1440,"description":"Minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false},{"type":"null"}]},"articleType":{"description":"Article type of articles created from the template. Only templates of a knowledge base have one; left out, a change keeps the current type.","anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}]}},"required":["name","category","title","fields","document"],"additionalProperties":false,"description":"A template."},"example":{"name":"Change request","description":"Planned change with risk and rollback","category":"operations","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]}}}}},"responses":{"200":{"description":"The template.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"ID of the template. Built-in templates have IDs starting with `builtin:`."},"level":{"type":"string","enum":["builtIn","instance","organization","space"],"description":"Where the template comes from: built in, or from the instance, the organization or the space."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization of an organization template, or null."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space of a space template, or null."},"name":{"type":"string","description":"Name."},"description":{"type":"string","description":"Short description."},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","description":"Title of new pages; `{key}` inserts the value of an input field."},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","description":"How often. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"Weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"Default rhythm."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Default duration in minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false,"description":"Defaults of a series template."},{"type":"null"}],"description":"For a series template: defaults for rhythm and duration of new meeting series; otherwise null."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Article type of articles created from a template of a knowledge base, or null."},"updatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the template last changed, or null for built-in templates. ISO 8601 timestamp in UTC."}},"required":["id","level","organizationId","spaceId","name","description","category","title","fields","document","series","articleType","updatedAt"],"additionalProperties":false,"description":"A page template."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","level":"instance","organizationId":null,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","name":"Change request","description":"Planned change with risk and rollback","category":"operations","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"series":null,"articleType":null,"updatedAt":"2026-10-05T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidDescription`: The description is too long. `invalidDocument`: The document does not match the editor schema. `invalidInput`: The request is not valid. `invalidTemplateFields`: The input fields of the template are not valid. `invalidTemplateName`: The template name is not valid. `invalidTitle`: The title is not valid. `unknownTemplateField`: The template uses an input field that does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidDescription":{"value":{"type":"urn:lunedo:problem:invalidDescription","title":"The description is too long","status":400,"code":"invalidDescription"}},"invalidDocument":{"value":{"type":"urn:lunedo:problem:invalidDocument","title":"The document does not match the editor schema","status":400,"code":"invalidDocument"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidTemplateFields":{"value":{"type":"urn:lunedo:problem:invalidTemplateFields","title":"The input fields of the template are not valid","status":400,"code":"invalidTemplateFields"}},"invalidTemplateName":{"value":{"type":"urn:lunedo:problem:invalidTemplateName","title":"The template name is not valid","status":400,"code":"invalidTemplateName"}},"invalidTitle":{"value":{"type":"urn:lunedo:problem:invalidTitle","title":"The title is not valid","status":400,"code":"invalidTitle"}},"unknownTemplateField":{"value":{"type":"urn:lunedo:problem:unknownTemplateField","title":"The template uses an input field that does not exist","status":400,"code":"unknownTemplateField"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/templates/{templateId}/files":{"post":{"operationId":"templateFiles.instanceUpload","summary":"Add an image to an instance template","description":"Stores an image for the template: PNG, JPEG, GIF, WebP or SVG up to 5 MB.\n\nRequires the permission `instance.templates.manage` on the instance.","tags":["Templates"],"x-lunedo-permission":{"action":"instance.templates.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"templateId","in":"path","required":true,"description":"ID of the template.","schema":{"type":"string","format":"uuid"}},{"name":"name","in":"query","required":true,"description":"Name of the uploaded file. Paths and control characters are removed.","schema":{"type":"string","minLength":1,"maxLength":1020}}],"requestBody":{"required":true,"description":"The bytes of the image.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"201":{"description":"The file.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the file. Content of the template refers to it, for example as `attachmentId` of an image."},"templateId":{"type":"string","format":"uuid","description":"ID of the template."},"name":{"type":"string","description":"File name."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size in bytes."},"contentType":{"type":"string","description":"Media type, decided from the content."}},"required":["id","templateId","name","size","contentType"],"additionalProperties":false,"description":"A file of a template."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a91","templateId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","name":"rollout.png","size":48213,"contentType":"image/png"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidFileName`: The file name is not valid. `invalidInput`: The request is not valid. `unsupportedTemplateFile`: Templates hold PNG, JPEG, GIF, WebP and SVG images only.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidFileName":{"value":{"type":"urn:lunedo:problem:invalidFileName","title":"The file name is not valid","status":400,"code":"invalidFileName"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"unsupportedTemplateFile":{"value":{"type":"urn:lunedo:problem:unsupportedTemplateFile","title":"Templates hold PNG, JPEG, GIF, WebP and SVG images only","status":400,"code":"unsupportedTemplateFile"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"408":{"description":"`uploadTimeout`: The upload took too long.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"uploadTimeout":{"value":{"type":"urn:lunedo:problem:uploadTimeout","title":"The upload took too long","status":408,"code":"uploadTimeout"}}}}}},"413":{"description":"`fileTooLarge`: The file is larger than allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"fileTooLarge":{"value":{"type":"urn:lunedo:problem:fileTooLarge","title":"The file is larger than allowed","status":413,"code":"fileTooLarge"}}}}}},"415":{"description":"`unsupportedMediaType`: The request body has an unsupported type.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unsupportedMediaType":{"value":{"type":"urn:lunedo:problem:unsupportedMediaType","title":"The request body has an unsupported type","status":415,"code":"unsupportedMediaType"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`busy`: The server is busy. `maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"busy":{"value":{"type":"urn:lunedo:problem:busy","title":"The server is busy","status":503,"code":"busy"}},"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}},"507":{"description":"`storageFull`: Storage is almost full.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"storageFull":{"value":{"type":"urn:lunedo:problem:storageFull","title":"Storage is almost full","status":507,"code":"storageFull"}}}}}}}}},"/api/v1/instance/templates/{templateId}/files/{fileId}/content":{"get":{"operationId":"templateFiles.instanceTemplateFile","summary":"Download a file of an instance template","description":"Sends a file of a template of the instance.\n\nRequires the permission `instance.templates.manage` on the instance.","tags":["Templates"],"x-lunedo-permission":{"action":"instance.templates.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"templateId","in":"path","required":true,"description":"ID of the template.","schema":{"type":"string","format":"uuid"}},{"name":"fileId","in":"path","required":true,"description":"ID of the file.","schema":{"type":"string","format":"uuid"}},{"name":"size","in":"query","required":false,"description":"Size of an image. `display` sends a version whose longest edge is at most 2048 pixels, `preview` one of at most 400 pixels, both as WebP without metadata. The original is sent while no such version exists, for images that are already small enough, and for every other type. Images above 100 megapixels get no smaller version and answer `imageTooLarge`.","schema":{"default":"original","type":"string","enum":["original","display","preview"]}}],"responses":{"200":{"description":"The file. Sent with `Content-Security-Policy: sandbox` and `X-Content-Type-Options: nosniff`; ranges are supported.","content":{"image/png":{"schema":{"type":"string"},"example":""},"image/jpeg":{"schema":{"type":"string"},"example":""},"image/gif":{"schema":{"type":"string"},"example":""},"image/webp":{"schema":{"type":"string"},"example":""},"image/svg+xml":{"schema":{"type":"string"},"example":""},"*/*":{"schema":{"type":"string"},"example":""}}},"206":{"description":"Part of the file, for a request with a `Range` header.","content":{"image/png":{"schema":{"type":"string"},"example":""},"image/jpeg":{"schema":{"type":"string"},"example":""},"image/gif":{"schema":{"type":"string"},"example":""},"image/webp":{"schema":{"type":"string"},"example":""},"image/svg+xml":{"schema":{"type":"string"},"example":""},"*/*":{"schema":{"type":"string"},"example":""}}},"304":{"description":"Not modified: the file matches the `If-None-Match` header."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`imageTooLarge`: The image is too large for a smaller version.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"imageTooLarge":{"value":{"type":"urn:lunedo:problem:imageTooLarge","title":"The image is too large for a smaller version","status":409,"code":"imageTooLarge"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/instance/templates/built-in/export":{"post":{"operationId":"templateFiles.builtInExport","summary":"Export built-in templates","description":"Sends built-in templates in the chosen language as a template file, as a starting point for own templates.\n\nRequires the permission `instance.templates.manage` on the instance.","tags":["Templates"],"x-lunedo-permission":{"action":"instance.templates.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"language":{"type":"string","enum":["en","de"],"description":"Language of the exported built-in templates."},"templateIds":{"default":null,"description":"The built-in templates to export, such as `builtin:how-to`; null for all.","anyOf":[{"minItems":1,"maxItems":50,"type":"array","items":{"type":"string","pattern":"^builtin:[a-z][a-z0-9-]{0,63}$","description":"ID of a built-in template."}},{"type":"null"}]}},"required":["language"],"additionalProperties":false,"description":"Which built-in templates to export, and in which language."},"example":{"language":"de","templateIds":["builtin:how-to"]}}}},"responses":{"200":{"description":"A template file: JSON for templates without files, otherwise a ZIP archive with `template.json` and the files under `files/`.","content":{"application/json":{"schema":{"type":"string"},"example":"{\n  \"format\": \"lunedo-template\",\n  \"formatVersion\": 1\n}\n"},"application/zip":{"schema":{"type":"string"},"example":"{\n  \"format\": \"lunedo-template\",\n  \"formatVersion\": 1\n}\n"}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `noTemplates`: There are no templates to export. `templateExportTooLarge`: The export would be larger than allowed. `tooManyTemplates`: The file holds more templates than allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"noTemplates":{"value":{"type":"urn:lunedo:problem:noTemplates","title":"There are no templates to export","status":400,"code":"noTemplates"}},"templateExportTooLarge":{"value":{"type":"urn:lunedo:problem:templateExportTooLarge","title":"The export would be larger than allowed","status":400,"code":"templateExportTooLarge"}},"tooManyTemplates":{"value":{"type":"urn:lunedo:problem:tooManyTemplates","title":"The file holds more templates than allowed","status":400,"code":"tooManyTemplates"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`templateNotFound`: The template does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"templateNotFound":{"value":{"type":"urn:lunedo:problem:templateNotFound","title":"The template does not exist","status":404,"code":"templateNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/templates/export":{"post":{"operationId":"templateFiles.instanceExport","summary":"Export instance templates","description":"Sends the chosen templates of the instance as a template file, cleaned like space templates.\n\nRequires the permission `instance.templates.manage` on the instance.","tags":["Templates"],"x-lunedo-permission":{"action":"instance.templates.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"templateIds":{"default":null,"description":"The templates to export; null for all of this level, at most 50.","anyOf":[{"minItems":1,"maxItems":50,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a template."}},{"type":"null"}]}},"additionalProperties":false,"description":"Which templates to export."},"example":{"templateIds":null}}}},"responses":{"200":{"description":"A template file: JSON for templates without files, otherwise a ZIP archive with `template.json` and the files under `files/`.","content":{"application/json":{"schema":{"type":"string"},"example":"{\n  \"format\": \"lunedo-template\",\n  \"formatVersion\": 1\n}\n"},"application/zip":{"schema":{"type":"string"},"example":"{\n  \"format\": \"lunedo-template\",\n  \"formatVersion\": 1\n}\n"}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `noTemplates`: There are no templates to export. `templateExportTooLarge`: The export would be larger than allowed. `tooManyTemplates`: The file holds more templates than allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"noTemplates":{"value":{"type":"urn:lunedo:problem:noTemplates","title":"There are no templates to export","status":400,"code":"noTemplates"}},"templateExportTooLarge":{"value":{"type":"urn:lunedo:problem:templateExportTooLarge","title":"The export would be larger than allowed","status":400,"code":"templateExportTooLarge"}},"tooManyTemplates":{"value":{"type":"urn:lunedo:problem:tooManyTemplates","title":"The file holds more templates than allowed","status":400,"code":"tooManyTemplates"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`templateNotFound`: The template does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"templateNotFound":{"value":{"type":"urn:lunedo:problem:templateNotFound","title":"The template does not exist","status":404,"code":"templateNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/templates/export-summary":{"post":{"operationId":"templateFiles.instanceExportSummary","summary":"Check an export of instance templates","description":"Tells per template what an export removes, before anything is downloaded.\n\nRequires the permission `instance.templates.manage` on the instance.","tags":["Templates"],"x-lunedo-permission":{"action":"instance.templates.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"templateIds":{"default":null,"description":"The templates to export; null for all of this level, at most 50.","anyOf":[{"minItems":1,"maxItems":50,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a template."}},{"type":"null"}]}},"additionalProperties":false,"description":"Which templates to export."},"example":{"templateIds":null}}}},"responses":{"200":{"description":"What the export contains.","content":{"application/json":{"schema":{"type":"object","properties":{"templates":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the template."},"files":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of files in the export."},"removed":{"type":"object","propertyNames":{"type":"string","enum":["pageLink","mention","include","diagramReference","whiteboard","templateButton","report","roadmap","person","comment","meetingTopic","file","unsupportedMacro"]},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"What is removed because it cannot work in another instance, by kind: `pageLink` (links to pages and spaces), `mention`, `include`, `diagramReference`, `whiteboard`, `templateButton`, `report`, `roadmap`, `person`, `comment`, `meetingTopic`, `file` (files that are not part of the template or not images) and `unsupportedMacro`."}},"required":["name","files","removed"],"additionalProperties":false,"description":"A template of the export."},"description":"The templates in the order of the file."}},"required":["templates"],"additionalProperties":false,"description":"What an export will contain."},"example":{"templates":[{"name":"Change request","files":1,"removed":{"pageLink":2,"mention":1}}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`templateNotFound`: The template does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"templateNotFound":{"value":{"type":"urn:lunedo:problem:templateNotFound","title":"The template does not exist","status":404,"code":"templateNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/instance/updates":{"get":{"operationId":"operations.updates","summary":"Get the running version and available updates","description":"Shows the running version, what is new in it, the result of the last update check, every release after the running version with its notes, breaking changes and manual steps, and the commands to update for the recorded installation method. The commands are built by Lunedo; nothing from the version file is executed or shown as HTML.\n\nRequires the permission `instance.operations.view` on the instance.","tags":["Operations"],"x-lunedo-permission":{"action":"instance.operations.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"200":{"description":"Version and updates.","content":{"application/json":{"schema":{"type":"object","properties":{"running":{"type":"string","description":"The running version. Builds without a release show a commit or `dev`."},"runningIsRelease":{"type":"boolean","description":"Whether the running version is a release that can be compared."},"check":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether the update check is on."},"disabledBy":{"anyOf":[{"type":"string","enum":["environment","setting"]},{"type":"null"}],"description":"What turned it off: `environment` for `LUNEDO_UPDATE_CHECK=false`, `setting` for the instance setting."},"url":{"type":"string","description":"The address of the version file."},"checkedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the last check ran, or null."},"succeeded":{"type":"boolean","description":"Whether the last check succeeded."},"failure":{"anyOf":[{"type":"string","enum":["unreachable","timeout","blockedAddress","insecureAddress","untrustedCertificate","tooManyRedirects","httpStatus","tooLarge","invalidFile"]},{"type":"null"}],"description":"Why the last check failed: `unreachable`, `timeout`, `blockedAddress`, `insecureAddress`, `untrustedCertificate`, `tooManyRedirects`, `httpStatus`, `tooLarge` or `invalidFile`."}},"required":["enabled","disabledBy","url","checkedAt","succeeded","failure"],"additionalProperties":false,"description":"The update check. It downloads a public version file and sends nothing beyond the request."},"latest":{"description":"The newest release after the running version, or null.","type":["string","null"]},"available":{"type":"array","items":{"type":"object","properties":{"version":{"type":"string","description":"The release version, for example `1.5.0`."},"date":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Release date."},"minimumUpdateFrom":{"description":"The oldest version that can update to this release directly, or null for any.","type":["string","null"]},"url":{"description":"Address of the release page, always HTTPS.","type":["string","null"]},"notes":{"type":"object","properties":{"new":{"type":"array","items":{"type":"string"},"description":"New features."},"improved":{"type":"array","items":{"type":"string"},"description":"Improvements."},"fixed":{"type":"array","items":{"type":"string"},"description":"Fixes."},"breaking":{"type":"array","items":{"type":"string"},"description":"Breaking changes to read before updating."},"manualSteps":{"type":"array","items":{"type":"string"},"description":"Steps the operator does by hand during the update."}},"required":["new","improved","fixed","breaking","manualSteps"],"additionalProperties":false,"description":"Release notes by group, as plain text."}},"required":["version","date","minimumUpdateFrom","url","notes"],"additionalProperties":false,"description":"A release."},"description":"Releases after the running version, oldest first."},"commands":{"anyOf":[{"type":"object","properties":{"method":{"type":"string","enum":["script","compose","other","unknown"],"description":"The recorded installation method, from `LUNEDO_INSTALL_METHOD`."},"steps":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["command","note"],"description":"`command` to run in a shell, `note` to do by hand."},"text":{"type":"string","description":"The command or the step."}},"required":["kind","text"],"additionalProperties":false},"description":"What to do, in order."}},"required":["method","steps"],"additionalProperties":false},{"type":"null"}],"description":"How to update to the newest release, built by Lunedo from the installation method."},"whatsNew":{"type":"object","properties":{"available":{"type":"boolean","description":"Whether the changelog is part of this image."},"version":{"description":"The section shown: the running version, or `Unreleased`.","type":["string","null"]},"date":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Release date of the running version."},"notes":{"anyOf":[{"type":"object","properties":{"new":{"type":"array","items":{"type":"string"},"description":"New features."},"improved":{"type":"array","items":{"type":"string"},"description":"Improvements."},"fixed":{"type":"array","items":{"type":"string"},"description":"Fixes."},"breaking":{"type":"array","items":{"type":"string"},"description":"Breaking changes to read before updating."},"manualSteps":{"type":"array","items":{"type":"string"},"description":"Steps the operator does by hand during the update."}},"required":["new","improved","fixed","breaking","manualSteps"],"additionalProperties":false},{"type":"null"}],"description":"Release notes by group, as plain text."}},"required":["available","version","date","notes"],"additionalProperties":false,"description":"What is new in the running version, from the changelog in the image. Works with the check off."}},"required":["running","runningIsRelease","check","latest","available","commands","whatsNew"],"additionalProperties":false,"description":"The running version, available updates and what is new."},"example":{"running":"1.4.2","runningIsRelease":true,"check":{"enabled":true,"disabledBy":null,"url":"https://github.com/lunedo/lunedo/releases/latest/download/lunedo-versions.json","checkedAt":"2026-11-03T04:11:00.000Z","succeeded":true,"failure":null},"latest":"1.5.0","available":[{"version":"1.5.0","date":"2026-11-02","minimumUpdateFrom":"1.3.0","url":"https://github.com/lunedo/lunedo/releases/tag/v1.5.0","notes":{"new":["Maintenance mode for scripted maintenance."],"improved":[],"fixed":[],"breaking":[],"manualSteps":[]}}],"commands":{"method":"script","steps":[{"kind":"command","text":"cd /opt/lunedo"},{"kind":"command","text":"./lunedo update 1.5.0"}]},"whatsNew":{"available":true,"version":"1.4.2","date":"2026-10-01","notes":{"new":[],"improved":[],"fixed":["Uploads through Nginx."],"breaking":[],"manualSteps":[]}}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/instance/updates/check":{"post":{"operationId":"operations.checkForUpdates","summary":"Check for updates now","description":"Downloads the version file now instead of waiting for the daily check. Does nothing when the update check is off. A failed check is not an error of this request; the result names the reason.\n\nRequires the permission `instance.operations.manage` on the instance.","tags":["Operations"],"x-lunedo-permission":{"action":"instance.operations.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"200":{"description":"Version and updates after the check.","content":{"application/json":{"schema":{"type":"object","properties":{"running":{"type":"string","description":"The running version. Builds without a release show a commit or `dev`."},"runningIsRelease":{"type":"boolean","description":"Whether the running version is a release that can be compared."},"check":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether the update check is on."},"disabledBy":{"anyOf":[{"type":"string","enum":["environment","setting"]},{"type":"null"}],"description":"What turned it off: `environment` for `LUNEDO_UPDATE_CHECK=false`, `setting` for the instance setting."},"url":{"type":"string","description":"The address of the version file."},"checkedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the last check ran, or null."},"succeeded":{"type":"boolean","description":"Whether the last check succeeded."},"failure":{"anyOf":[{"type":"string","enum":["unreachable","timeout","blockedAddress","insecureAddress","untrustedCertificate","tooManyRedirects","httpStatus","tooLarge","invalidFile"]},{"type":"null"}],"description":"Why the last check failed: `unreachable`, `timeout`, `blockedAddress`, `insecureAddress`, `untrustedCertificate`, `tooManyRedirects`, `httpStatus`, `tooLarge` or `invalidFile`."}},"required":["enabled","disabledBy","url","checkedAt","succeeded","failure"],"additionalProperties":false,"description":"The update check. It downloads a public version file and sends nothing beyond the request."},"latest":{"description":"The newest release after the running version, or null.","type":["string","null"]},"available":{"type":"array","items":{"type":"object","properties":{"version":{"type":"string","description":"The release version, for example `1.5.0`."},"date":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Release date."},"minimumUpdateFrom":{"description":"The oldest version that can update to this release directly, or null for any.","type":["string","null"]},"url":{"description":"Address of the release page, always HTTPS.","type":["string","null"]},"notes":{"type":"object","properties":{"new":{"type":"array","items":{"type":"string"},"description":"New features."},"improved":{"type":"array","items":{"type":"string"},"description":"Improvements."},"fixed":{"type":"array","items":{"type":"string"},"description":"Fixes."},"breaking":{"type":"array","items":{"type":"string"},"description":"Breaking changes to read before updating."},"manualSteps":{"type":"array","items":{"type":"string"},"description":"Steps the operator does by hand during the update."}},"required":["new","improved","fixed","breaking","manualSteps"],"additionalProperties":false,"description":"Release notes by group, as plain text."}},"required":["version","date","minimumUpdateFrom","url","notes"],"additionalProperties":false,"description":"A release."},"description":"Releases after the running version, oldest first."},"commands":{"anyOf":[{"type":"object","properties":{"method":{"type":"string","enum":["script","compose","other","unknown"],"description":"The recorded installation method, from `LUNEDO_INSTALL_METHOD`."},"steps":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["command","note"],"description":"`command` to run in a shell, `note` to do by hand."},"text":{"type":"string","description":"The command or the step."}},"required":["kind","text"],"additionalProperties":false},"description":"What to do, in order."}},"required":["method","steps"],"additionalProperties":false},{"type":"null"}],"description":"How to update to the newest release, built by Lunedo from the installation method."},"whatsNew":{"type":"object","properties":{"available":{"type":"boolean","description":"Whether the changelog is part of this image."},"version":{"description":"The section shown: the running version, or `Unreleased`.","type":["string","null"]},"date":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Release date of the running version."},"notes":{"anyOf":[{"type":"object","properties":{"new":{"type":"array","items":{"type":"string"},"description":"New features."},"improved":{"type":"array","items":{"type":"string"},"description":"Improvements."},"fixed":{"type":"array","items":{"type":"string"},"description":"Fixes."},"breaking":{"type":"array","items":{"type":"string"},"description":"Breaking changes to read before updating."},"manualSteps":{"type":"array","items":{"type":"string"},"description":"Steps the operator does by hand during the update."}},"required":["new","improved","fixed","breaking","manualSteps"],"additionalProperties":false},{"type":"null"}],"description":"Release notes by group, as plain text."}},"required":["available","version","date","notes"],"additionalProperties":false,"description":"What is new in the running version, from the changelog in the image. Works with the check off."}},"required":["running","runningIsRelease","check","latest","available","commands","whatsNew"],"additionalProperties":false,"description":"The running version, available updates and what is new."},"example":{"running":"1.4.2","runningIsRelease":true,"check":{"enabled":true,"disabledBy":null,"url":"https://github.com/lunedo/lunedo/releases/latest/download/lunedo-versions.json","checkedAt":"2026-11-03T04:11:00.000Z","succeeded":true,"failure":null},"latest":"1.5.0","available":[{"version":"1.5.0","date":"2026-11-02","minimumUpdateFrom":"1.3.0","url":"https://github.com/lunedo/lunedo/releases/tag/v1.5.0","notes":{"new":["Maintenance mode for scripted maintenance."],"improved":[],"fixed":[],"breaking":[],"manualSteps":[]}}],"commands":{"method":"script","steps":[{"kind":"command","text":"cd /opt/lunedo"},{"kind":"command","text":"./lunedo update 1.5.0"}]},"whatsNew":{"available":true,"version":"1.4.2","date":"2026-10-01","notes":{"new":[],"improved":[],"fixed":["Uploads through Nginx."],"breaking":[],"manualSteps":[]}}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/items":{"get":{"operationId":"items.search","summary":"Find pages and folders by title","description":"Searches the titles of items the caller can read, in all spaces or in one.\n\nRequires the permission `instance.content.view` on the instance.","tags":["Pages"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"q","in":"query","required":false,"description":"Text the title contains.","schema":{"default":"","type":"string","maxLength":200}},{"name":"spaceId","in":"query","required":false,"description":"Only items of this space.","schema":{"type":"string","format":"uuid"}},{"name":"kind","in":"query","required":false,"description":"Only items of this kind. Without it, pages and folders are searched.","schema":{"type":"string","enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]}},{"name":"limit","in":"query","required":false,"description":"Maximum number of results, 1 to 50.","schema":{"default":20,"type":"integer","minimum":1,"maximum":50}}],"responses":{"200":{"description":"Found items, best matches first.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the item."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app, unique in the instance. It never changes and is never reused."},"spaceId":{"type":"string","format":"uuid","description":"Space of the item."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Parent item, or null at the root of the tree."},"kind":{"type":"string","description":"`page`, `folder`, `link`, `blogPost`, `meetingSeries`, `meetingTopic` or `whiteboard`. Blog posts and topics are not part of the tree; they appear in the blog and the meetings of their space. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title. Empty for a link to content the caller cannot read."},"description":{"type":"string","description":"Short description of a folder."},"width":{"type":"string","enum":["fixed","full"],"description":"Page width: `fixed` or `full`."},"numberHeadings":{"type":"boolean","description":"Whether the headings of the page are numbered in the page, in print and in Word."},"mode":{"type":"string","enum":["publish","live"],"description":"Editing mode of a page: `publish` (readers see the last published version while editors work on a draft) or `live` (readers see every change at once). Folders and links are always `live`."},"published":{"type":"boolean","description":"Whether readers can see the page. False for a page in publish mode that was never published; only editors see it."},"archived":{"type":"boolean","description":"Whether the item is archived. Archived items are read-only."},"position":{"type":"string","description":"Sort key among the siblings. Items sort by it in binary order."},"hasChildren":{"type":"boolean","description":"Whether the item has children."},"viewRestriction":{"type":"string","enum":["none","own","inherited"],"description":"Whether only an access list may view the item: set on the item itself, on a page above, or not at all."},"editRestricted":{"type":"boolean","description":"Whether only an access list may edit the item."},"link":{"anyOf":[{"type":"object","properties":{"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Linked page, folder or whiteboard, or null for an address or when the caller cannot read it."},"url":{"description":"Linked `http` or `https` address, or null.","type":["string","null"]},"accessible":{"type":"boolean","description":"Whether the caller can open the target. If not, the title is empty."},"inTrash":{"type":"boolean","description":"Whether the target is in the trash. Only true for callers who could read it before."},"target":{"anyOf":[{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"Space of the target."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the target in the addresses of the app."},"spaceKey":{"type":"string","description":"Key of that space."},"kind":{"type":"string","description":"Kind of the target. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title of the target."}},"required":["spaceId","number","spaceKey","kind","title"],"additionalProperties":false},{"type":"null"}],"description":"The linked page, folder or whiteboard, or null."}},"required":["itemId","url","accessible","inTrash","target"],"additionalProperties":false,"description":"Where a link in the page tree points."},{"type":"null"}],"description":"Target of a link, or null for pages and folders."},"creatorId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Account that created the item, or null."},"contentLanguage":{"anyOf":[{"type":"string","description":"Content language as an ISO 639-1 code, or `other` for a language without its own word matching. Words are then matched as written. New values can be added in later versions; handle unknown values.","x-extensible-enum":["ar","ca","da","de","el","en","es","eu","fi","fr","ga","hi","hu","hy","id","it","lt","nb","ne","nl","pt","ro","ru","sr","sv","ta","tr","yi","other"]},{"type":"null"}],"description":"Language of the page content for search, or null to use the language of the space."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Type of an article in a knowledge base, or null for other items and articles without a type."},"translationOf":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Original article of a translation in a knowledge base, or null. A translation is listed below its original; `contentLanguage` is its language."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of the item, or null. The owner stays set when the person leaves; `owner.active` in the item details says whether the item has an active owner."},"status":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the status value."},"builtIn":{"anyOf":[{"type":"string","x-extensible-enum":["roughDraft","inProgress","readyForReview","verified"]},{"type":"null"}],"description":"Which default value this is, or null for a value a space admin added. Clients show the translated name of a default value unless `name` is set. New values can be added in later versions; handle unknown values."},"name":{"description":"Name set by a space admin, or null to show the default name.","type":["string","null"]},"color":{"type":"string","enum":["neutral","accent","info","success","warning","danger"],"description":"Color of the status: `neutral`, `accent`, `info`, `success`, `warning` or `danger`."}},"required":["id","builtIn","name","color"],"additionalProperties":false,"description":"A page status."},{"type":"null"}],"description":"Status of a page, or null when it has none or page status is turned off in the space."},"createdAt":{"type":"string","format":"date-time","description":"When the item was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the item last changed in the tree. ISO 8601 timestamp in UTC."},"contentUpdatedAt":{"type":"string","format":"date-time","description":"When the content of the page last changed. ISO 8601 timestamp in UTC."},"spaceKey":{"type":"string","description":"Key of the item's space."},"spaceName":{"type":"string","description":"Name of the item's space."}},"required":["id","number","spaceId","parentId","kind","title","description","width","numberHeadings","mode","published","archived","position","hasChildren","viewRestriction","editRestricted","link","creatorId","contentLanguage","articleType","translationOf","ownerId","status","createdAt","updatedAt","contentUpdatedAt","spaceKey","spaceName"],"additionalProperties":false,"description":"A found item."},"description":"Found items."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","parentId":null,"kind":"page","title":"VPN access for remote staff","description":"","width":"fixed","numberHeadings":false,"mode":"publish","published":true,"archived":false,"position":"a1","hasChildren":false,"viewRestriction":"none","editRestricted":false,"link":null,"creatorId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","ownerId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","contentLanguage":null,"articleType":null,"translationOf":null,"status":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","builtIn":"verified","name":null,"color":"success"},"createdAt":"2026-10-05T08:00:00.000Z","updatedAt":"2026-10-05T08:00:00.000Z","contentUpdatedAt":"2026-10-05T08:00:00.000Z","spaceKey":"ITOPS","spaceName":"IT Operations"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/items/{itemId}":{"delete":{"operationId":"items.delete","summary":"Delete an item","description":"Moves a page, folder or link with all its descendants into the trash of the space as one entry. Restore it from the trash to undo. The overview page of a space cannot be deleted.\n\nRequires the permission `item.delete` on the item in `itemId`.","tags":["Pages"],"x-lunedo-permission":{"action":"item.delete","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the page, folder or link.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The trash entry.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the trash entry."},"spaceId":{"type":"string","format":"uuid","description":"Space of the entry."},"spaceKey":{"type":"string","description":"Key of the space."},"spaceName":{"type":"string","description":"Name of the space."},"kind":{"type":"string","enum":["items","space"],"description":"`items` for deleted pages, folders or links, `space` for a deleted space."},"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The deleted item, or null for a space."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the deleted item in the addresses of the app, or null for a space."},"itemKind":{"anyOf":[{"type":"string","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},{"type":"null"}],"description":"Kind of the deleted item, or null for a space. New values can be added in later versions; handle unknown values."},"title":{"type":"string","description":"Title of the deleted item, or name of the space."},"descendants":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of descendants deleted with the item."},"stage":{"anyOf":[{"type":"number","const":1},{"type":"number","const":2}],"description":"1 while the entry is in the space trash, 2 after that period or after the trash was emptied; then only organization administrators can restore it."},"deletedAt":{"type":"string","format":"date-time","description":"When it was deleted. ISO 8601 timestamp in UTC."},"deletedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when the account no longer exists.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who deleted it."},"stageTwoAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the entry reached stage 2, or null. ISO 8601 timestamp in UTC."},"removedAt":{"type":"string","format":"date-time","description":"When the entry will be deleted permanently, by the current retention settings. ISO 8601 timestamp in UTC."},"formerParentEntryId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The trash entry of the page or folder this item was below, when that one is in the same trash list; restoring with `withParents=true` restores both. Null otherwise."}},"required":["id","spaceId","spaceKey","spaceName","kind","itemId","number","itemKind","title","descendants","stage","deletedAt","deletedBy","stageTwoAt","removedAt","formerParentEntryId"],"additionalProperties":false,"description":"An entry of the trash."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","kind":"items","itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a41","number":1041,"itemKind":"page","title":"Old VPN (OpenVPN) setup","descendants":2,"stage":1,"deletedAt":"2026-10-02T10:00:00.000Z","deletedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Lukas Hofer"},"stageTwoAt":null,"removedAt":"2027-02-14T10:00:00.000Z","formerParentEntryId":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`overviewPage`: The overview page of a space stays a page in its space.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"overviewPage":{"value":{"type":"urn:lunedo:problem:overviewPage","title":"The overview page of a space stays a page in its space","status":409,"code":"overviewPage"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"get":{"operationId":"items.get","summary":"Get an item of the page tree","description":"Returns a page, folder or link with its space and ancestors.\n\nRequires the permission `item.view` on the item in `itemId`.","tags":["Pages"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the page, folder or link.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The item.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the item."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app, unique in the instance. It never changes and is never reused."},"spaceId":{"type":"string","format":"uuid","description":"Space of the item."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Parent item, or null at the root of the tree."},"kind":{"type":"string","description":"`page`, `folder`, `link`, `blogPost`, `meetingSeries`, `meetingTopic` or `whiteboard`. Blog posts and topics are not part of the tree; they appear in the blog and the meetings of their space. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title. Empty for a link to content the caller cannot read."},"description":{"type":"string","description":"Short description of a folder."},"width":{"type":"string","enum":["fixed","full"],"description":"Page width: `fixed` or `full`."},"numberHeadings":{"type":"boolean","description":"Whether the headings of the page are numbered in the page, in print and in Word."},"mode":{"type":"string","enum":["publish","live"],"description":"Editing mode of a page: `publish` (readers see the last published version while editors work on a draft) or `live` (readers see every change at once). Folders and links are always `live`."},"published":{"type":"boolean","description":"Whether readers can see the page. False for a page in publish mode that was never published; only editors see it."},"archived":{"type":"boolean","description":"Whether the item is archived. Archived items are read-only."},"position":{"type":"string","description":"Sort key among the siblings. Items sort by it in binary order."},"hasChildren":{"type":"boolean","description":"Whether the item has children."},"viewRestriction":{"type":"string","enum":["none","own","inherited"],"description":"Whether only an access list may view the item: set on the item itself, on a page above, or not at all."},"editRestricted":{"type":"boolean","description":"Whether only an access list may edit the item."},"link":{"anyOf":[{"type":"object","properties":{"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Linked page, folder or whiteboard, or null for an address or when the caller cannot read it."},"url":{"description":"Linked `http` or `https` address, or null.","type":["string","null"]},"accessible":{"type":"boolean","description":"Whether the caller can open the target. If not, the title is empty."},"inTrash":{"type":"boolean","description":"Whether the target is in the trash. Only true for callers who could read it before."},"target":{"anyOf":[{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"Space of the target."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the target in the addresses of the app."},"spaceKey":{"type":"string","description":"Key of that space."},"kind":{"type":"string","description":"Kind of the target. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title of the target."}},"required":["spaceId","number","spaceKey","kind","title"],"additionalProperties":false},{"type":"null"}],"description":"The linked page, folder or whiteboard, or null."}},"required":["itemId","url","accessible","inTrash","target"],"additionalProperties":false,"description":"Where a link in the page tree points."},{"type":"null"}],"description":"Target of a link, or null for pages and folders."},"creatorId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Account that created the item, or null."},"contentLanguage":{"anyOf":[{"type":"string","description":"Content language as an ISO 639-1 code, or `other` for a language without its own word matching. Words are then matched as written. New values can be added in later versions; handle unknown values.","x-extensible-enum":["ar","ca","da","de","el","en","es","eu","fi","fr","ga","hi","hu","hy","id","it","lt","nb","ne","nl","pt","ro","ru","sr","sv","ta","tr","yi","other"]},{"type":"null"}],"description":"Language of the page content for search, or null to use the language of the space."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Type of an article in a knowledge base, or null for other items and articles without a type."},"translationOf":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Original article of a translation in a knowledge base, or null. A translation is listed below its original; `contentLanguage` is its language."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of the item, or null. The owner stays set when the person leaves; `owner.active` in the item details says whether the item has an active owner."},"status":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the status value."},"builtIn":{"anyOf":[{"type":"string","x-extensible-enum":["roughDraft","inProgress","readyForReview","verified"]},{"type":"null"}],"description":"Which default value this is, or null for a value a space admin added. Clients show the translated name of a default value unless `name` is set. New values can be added in later versions; handle unknown values."},"name":{"description":"Name set by a space admin, or null to show the default name.","type":["string","null"]},"color":{"type":"string","enum":["neutral","accent","info","success","warning","danger"],"description":"Color of the status: `neutral`, `accent`, `info`, `success`, `warning` or `danger`."}},"required":["id","builtIn","name","color"],"additionalProperties":false,"description":"A page status."},{"type":"null"}],"description":"Status of a page, or null when it has none or page status is turned off in the space."},"createdAt":{"type":"string","format":"date-time","description":"When the item was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the item last changed in the tree. ISO 8601 timestamp in UTC."},"contentUpdatedAt":{"type":"string","format":"date-time","description":"When the content of the page last changed. ISO 8601 timestamp in UTC."},"spaceKey":{"type":"string","description":"Key of the space. Empty when the caller sees the item only through a share or link."},"spaceName":{"type":"string","description":"Name of the space. Empty when the caller sees the item only through a share or link."},"spaceAccess":{"type":"boolean","description":"Whether the caller has access to the space; false when the item is visible only through a share or link."},"spaceContentLanguage":{"type":"string","description":"Content language of the space, which pages without a content language of their own use for search.","x-extensible-enum":["ar","ca","da","de","el","en","es","eu","fi","fr","ga","hi","hu","hy","id","it","lt","nb","ne","nl","pt","ro","ru","sr","sv","ta","tr","yi","other"]},"ancestors":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the ancestor."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the ancestor in the addresses of the app."},"kind":{"type":"string","description":"Kind of the ancestor. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title of the ancestor."},"published":{"type":"boolean","description":"Whether the ancestor counts as published: a folder, a link, a page in live mode or a page with a published version. Readers see a page only when every ancestor is published."}},"required":["id","number","kind","title","published"],"additionalProperties":false,"description":"An ancestor."},"description":"Ancestors from the root down to the parent."},"owner":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the owner."},"name":{"description":"Name of the owner, or null when the caller may not see the person.","type":["string","null"]},"jobTitle":{"description":"Job title the person entered on their profile, or null.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null without one. Changes whenever the picture changes; load the picture from `GET /api/v1/accounts/{accountId}/picture`.","type":["string","null"]},"email":{"description":"E-mail address of the owner, or null when the caller may not see it.","type":["string","null"]},"active":{"type":"boolean","description":"Whether the owner can still act: false when the account is deactivated or its membership in the organization ended."}},"required":["id","name","jobTitle","pictureRef","email","active"],"additionalProperties":false},{"type":"null"}],"description":"Owner of the item, or null when it has none."},"ownershipTransferable":{"type":"boolean","description":"Whether the caller may give the item a new owner."}},"required":["id","number","spaceId","parentId","kind","title","description","width","numberHeadings","mode","published","archived","position","hasChildren","viewRestriction","editRestricted","link","creatorId","contentLanguage","articleType","translationOf","ownerId","status","createdAt","updatedAt","contentUpdatedAt","spaceKey","spaceName","spaceAccess","spaceContentLanguage","ancestors","owner","ownershipTransferable"],"additionalProperties":false,"description":"An item with its place in the tree."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","parentId":null,"kind":"page","title":"VPN access for remote staff","description":"","width":"fixed","numberHeadings":false,"mode":"publish","published":true,"archived":false,"position":"a1","hasChildren":false,"viewRestriction":"none","editRestricted":false,"link":null,"creatorId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","ownerId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","contentLanguage":null,"articleType":null,"translationOf":null,"status":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","builtIn":"verified","name":null,"color":"success"},"createdAt":"2026-10-05T08:00:00.000Z","updatedAt":"2026-10-05T08:00:00.000Z","contentUpdatedAt":"2026-10-05T08:00:00.000Z","spaceKey":"ITOPS","spaceName":"IT Operations","spaceAccess":true,"spaceContentLanguage":"en","ancestors":[],"owner":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Weber","jobTitle":"Service Manager","pictureRef":null,"email":"anna.weber@example.org","active":true},"ownershipTransferable":true}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"patch":{"operationId":"items.update","summary":"Change an item","description":"Changes the title, the description of a folder, or the width and heading numbers of a page.\n\nRequires the permission `item.edit` on the item in `itemId`.","tags":["Pages"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the page, folder or link.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"description":"New title, 1 to 255 characters.","type":"string","maxLength":255},"description":{"description":"New description of a folder, up to 1000 characters.","type":"string","maxLength":1000},"width":{"description":"Page width: `fixed` or `full`.","type":"string","enum":["fixed","full"]},"numberHeadings":{"description":"Whether to number the headings of the page in the page, in print and in Word.","type":"boolean"}},"additionalProperties":false,"description":"Fields to change."},"example":{"title":"VPN access"}}}},"responses":{"200":{"description":"The changed item.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the item."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app, unique in the instance. It never changes and is never reused."},"spaceId":{"type":"string","format":"uuid","description":"Space of the item."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Parent item, or null at the root of the tree."},"kind":{"type":"string","description":"`page`, `folder`, `link`, `blogPost`, `meetingSeries`, `meetingTopic` or `whiteboard`. Blog posts and topics are not part of the tree; they appear in the blog and the meetings of their space. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title. Empty for a link to content the caller cannot read."},"description":{"type":"string","description":"Short description of a folder."},"width":{"type":"string","enum":["fixed","full"],"description":"Page width: `fixed` or `full`."},"numberHeadings":{"type":"boolean","description":"Whether the headings of the page are numbered in the page, in print and in Word."},"mode":{"type":"string","enum":["publish","live"],"description":"Editing mode of a page: `publish` (readers see the last published version while editors work on a draft) or `live` (readers see every change at once). Folders and links are always `live`."},"published":{"type":"boolean","description":"Whether readers can see the page. False for a page in publish mode that was never published; only editors see it."},"archived":{"type":"boolean","description":"Whether the item is archived. Archived items are read-only."},"position":{"type":"string","description":"Sort key among the siblings. Items sort by it in binary order."},"hasChildren":{"type":"boolean","description":"Whether the item has children."},"viewRestriction":{"type":"string","enum":["none","own","inherited"],"description":"Whether only an access list may view the item: set on the item itself, on a page above, or not at all."},"editRestricted":{"type":"boolean","description":"Whether only an access list may edit the item."},"link":{"anyOf":[{"type":"object","properties":{"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Linked page, folder or whiteboard, or null for an address or when the caller cannot read it."},"url":{"description":"Linked `http` or `https` address, or null.","type":["string","null"]},"accessible":{"type":"boolean","description":"Whether the caller can open the target. If not, the title is empty."},"inTrash":{"type":"boolean","description":"Whether the target is in the trash. Only true for callers who could read it before."},"target":{"anyOf":[{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"Space of the target."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the target in the addresses of the app."},"spaceKey":{"type":"string","description":"Key of that space."},"kind":{"type":"string","description":"Kind of the target. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title of the target."}},"required":["spaceId","number","spaceKey","kind","title"],"additionalProperties":false},{"type":"null"}],"description":"The linked page, folder or whiteboard, or null."}},"required":["itemId","url","accessible","inTrash","target"],"additionalProperties":false,"description":"Where a link in the page tree points."},{"type":"null"}],"description":"Target of a link, or null for pages and folders."},"creatorId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Account that created the item, or null."},"contentLanguage":{"anyOf":[{"type":"string","description":"Content language as an ISO 639-1 code, or `other` for a language without its own word matching. Words are then matched as written. New values can be added in later versions; handle unknown values.","x-extensible-enum":["ar","ca","da","de","el","en","es","eu","fi","fr","ga","hi","hu","hy","id","it","lt","nb","ne","nl","pt","ro","ru","sr","sv","ta","tr","yi","other"]},{"type":"null"}],"description":"Language of the page content for search, or null to use the language of the space."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Type of an article in a knowledge base, or null for other items and articles without a type."},"translationOf":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Original article of a translation in a knowledge base, or null. A translation is listed below its original; `contentLanguage` is its language."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of the item, or null. The owner stays set when the person leaves; `owner.active` in the item details says whether the item has an active owner."},"status":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the status value."},"builtIn":{"anyOf":[{"type":"string","x-extensible-enum":["roughDraft","inProgress","readyForReview","verified"]},{"type":"null"}],"description":"Which default value this is, or null for a value a space admin added. Clients show the translated name of a default value unless `name` is set. New values can be added in later versions; handle unknown values."},"name":{"description":"Name set by a space admin, or null to show the default name.","type":["string","null"]},"color":{"type":"string","enum":["neutral","accent","info","success","warning","danger"],"description":"Color of the status: `neutral`, `accent`, `info`, `success`, `warning` or `danger`."}},"required":["id","builtIn","name","color"],"additionalProperties":false,"description":"A page status."},{"type":"null"}],"description":"Status of a page, or null when it has none or page status is turned off in the space."},"createdAt":{"type":"string","format":"date-time","description":"When the item was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the item last changed in the tree. ISO 8601 timestamp in UTC."},"contentUpdatedAt":{"type":"string","format":"date-time","description":"When the content of the page last changed. ISO 8601 timestamp in UTC."}},"required":["id","number","spaceId","parentId","kind","title","description","width","numberHeadings","mode","published","archived","position","hasChildren","viewRestriction","editRestricted","link","creatorId","contentLanguage","articleType","translationOf","ownerId","status","createdAt","updatedAt","contentUpdatedAt"],"additionalProperties":false,"description":"An item of the page tree."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","parentId":null,"kind":"page","title":"VPN access for remote staff","description":"","width":"fixed","numberHeadings":false,"mode":"publish","published":true,"archived":false,"position":"a1","hasChildren":false,"viewRestriction":"none","editRestricted":false,"link":null,"creatorId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","ownerId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","contentLanguage":null,"articleType":null,"translationOf":null,"status":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","builtIn":"verified","name":null,"color":"success"},"createdAt":"2026-10-05T08:00:00.000Z","updatedAt":"2026-10-05T08:00:00.000Z","contentUpdatedAt":"2026-10-05T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidDescription`: The description is too long. `invalidInput`: The request is not valid. `invalidTitle`: The title is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidDescription":{"value":{"type":"urn:lunedo:problem:invalidDescription","title":"The description is too long","status":400,"code":"invalidDescription"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidTitle":{"value":{"type":"urn:lunedo:problem:invalidTitle","title":"The title is not valid","status":400,"code":"invalidTitle"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/items/{itemId}/activity":{"get":{"operationId":"ownership.activity","summary":"List status and owner changes and reviews of an item","description":"Returns who changed the status or the owner of the item, or reviewed the article, and when, newest first.\n\nRequires the permission `item.view` on the item in `itemId`.","tags":["Ownership and status"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the page, folder, link, blog post or meeting series.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The changes.","content":{"application/json":{"schema":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"status","description":"The status changed."},"id":{"type":"string","format":"uuid","description":"ID of the entry."},"status":{"anyOf":[{"type":"object","properties":{"id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the status value, or null when it was removed since."},"builtIn":{"anyOf":[{"type":"string","x-extensible-enum":["roughDraft","inProgress","readyForReview","verified"]},{"type":"null"}],"description":"Which default value this is, or null for a value a space admin added. Clients show the translated name of a default value unless `name` is set. New values can be added in later versions; handle unknown values."},"name":{"description":"Name set by a space admin, or null to show the default name.","type":["string","null"]},"color":{"type":"string","enum":["neutral","accent","info","success","warning","danger"],"description":"Color of the status: `neutral`, `accent`, `info`, `success`, `warning` or `danger`."}},"required":["id","builtIn","name","color"],"additionalProperties":false},{"type":"null"}],"description":"The new status, or null when it was removed."},"actor":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the person."},"name":{"description":"Name of the person, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who changed it, or null for an import."},"at":{"type":"string","format":"date-time","description":"When it changed. ISO 8601 timestamp in UTC."}},"required":["type","id","status","actor","at"],"additionalProperties":false,"description":"A status change."},{"type":"object","properties":{"type":{"type":"string","const":"owner","description":"The owner changed."},"id":{"type":"string","format":"uuid","description":"ID of the entry."},"previousOwner":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the person."},"name":{"description":"Name of the person, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"The owner before, or null."},"owner":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the person."},"name":{"description":"Name of the person, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"The new owner."},"actor":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the person."},"name":{"description":"Name of the person, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who changed it."},"at":{"type":"string","format":"date-time","description":"When it changed. ISO 8601 timestamp in UTC."}},"required":["type","id","previousOwner","owner","actor","at"],"additionalProperties":false,"description":"A change of owner."},{"type":"object","properties":{"type":{"type":"string","const":"review","description":"The article was marked as reviewed."},"id":{"type":"string","format":"uuid","description":"ID of the review."},"via":{"type":"string","enum":["marked","published"],"description":"`marked` without a change, or `published` with a publication the author marked as reviewed."},"actor":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the person."},"name":{"description":"Name of the person, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who reviewed it."},"at":{"type":"string","format":"date-time","description":"When it was reviewed. ISO 8601 timestamp in UTC."}},"required":["type","id","via","actor","at"],"additionalProperties":false,"description":"A review of a knowledge base article."}],"description":"An entry of the activity."},"description":"Status and owner changes and reviews of the item, newest first."},"example":[{"type":"status","id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","status":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","builtIn":"verified","name":null,"color":"success"},"actor":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Weber"},"at":"2026-10-05T08:00:00.000Z"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/items/{itemId}/archive":{"post":{"operationId":"items.archive","summary":"Archive an item","description":"Archives a page or folder with its descendants. They become read-only, leave the page tree and appear in the archive of the space. Versions and links stay.\n\nRequires the permission `item.archive` on the item in `itemId`.","tags":["Pages"],"x-lunedo-permission":{"action":"item.archive","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the page, folder or link.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`overviewPage`: The overview page of a space stays a page in its space.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"overviewPage":{"value":{"type":"urn:lunedo:problem:overviewPage","title":"The overview page of a space stays a page in its space","status":409,"code":"overviewPage"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/items/{itemId}/convert":{"post":{"operationId":"items.convert","summary":"Convert between page and folder","description":"Turns a folder into a page or a page into a folder. Children stay where they are.\n\nRequires the permission `item.edit` on the item in `itemId`.","tags":["Pages"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the page, folder or link.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["page","folder"],"description":"The new kind. Children are kept."}},"required":["kind"],"additionalProperties":false,"description":"The kind to convert to."},"example":{"kind":"folder"}}}},"responses":{"200":{"description":"The converted item.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the item."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app, unique in the instance. It never changes and is never reused."},"spaceId":{"type":"string","format":"uuid","description":"Space of the item."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Parent item, or null at the root of the tree."},"kind":{"type":"string","description":"`page`, `folder`, `link`, `blogPost`, `meetingSeries`, `meetingTopic` or `whiteboard`. Blog posts and topics are not part of the tree; they appear in the blog and the meetings of their space. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title. Empty for a link to content the caller cannot read."},"description":{"type":"string","description":"Short description of a folder."},"width":{"type":"string","enum":["fixed","full"],"description":"Page width: `fixed` or `full`."},"numberHeadings":{"type":"boolean","description":"Whether the headings of the page are numbered in the page, in print and in Word."},"mode":{"type":"string","enum":["publish","live"],"description":"Editing mode of a page: `publish` (readers see the last published version while editors work on a draft) or `live` (readers see every change at once). Folders and links are always `live`."},"published":{"type":"boolean","description":"Whether readers can see the page. False for a page in publish mode that was never published; only editors see it."},"archived":{"type":"boolean","description":"Whether the item is archived. Archived items are read-only."},"position":{"type":"string","description":"Sort key among the siblings. Items sort by it in binary order."},"hasChildren":{"type":"boolean","description":"Whether the item has children."},"viewRestriction":{"type":"string","enum":["none","own","inherited"],"description":"Whether only an access list may view the item: set on the item itself, on a page above, or not at all."},"editRestricted":{"type":"boolean","description":"Whether only an access list may edit the item."},"link":{"anyOf":[{"type":"object","properties":{"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Linked page, folder or whiteboard, or null for an address or when the caller cannot read it."},"url":{"description":"Linked `http` or `https` address, or null.","type":["string","null"]},"accessible":{"type":"boolean","description":"Whether the caller can open the target. If not, the title is empty."},"inTrash":{"type":"boolean","description":"Whether the target is in the trash. Only true for callers who could read it before."},"target":{"anyOf":[{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"Space of the target."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the target in the addresses of the app."},"spaceKey":{"type":"string","description":"Key of that space."},"kind":{"type":"string","description":"Kind of the target. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title of the target."}},"required":["spaceId","number","spaceKey","kind","title"],"additionalProperties":false},{"type":"null"}],"description":"The linked page, folder or whiteboard, or null."}},"required":["itemId","url","accessible","inTrash","target"],"additionalProperties":false,"description":"Where a link in the page tree points."},{"type":"null"}],"description":"Target of a link, or null for pages and folders."},"creatorId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Account that created the item, or null."},"contentLanguage":{"anyOf":[{"type":"string","description":"Content language as an ISO 639-1 code, or `other` for a language without its own word matching. Words are then matched as written. New values can be added in later versions; handle unknown values.","x-extensible-enum":["ar","ca","da","de","el","en","es","eu","fi","fr","ga","hi","hu","hy","id","it","lt","nb","ne","nl","pt","ro","ru","sr","sv","ta","tr","yi","other"]},{"type":"null"}],"description":"Language of the page content for search, or null to use the language of the space."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Type of an article in a knowledge base, or null for other items and articles without a type."},"translationOf":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Original article of a translation in a knowledge base, or null. A translation is listed below its original; `contentLanguage` is its language."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of the item, or null. The owner stays set when the person leaves; `owner.active` in the item details says whether the item has an active owner."},"status":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the status value."},"builtIn":{"anyOf":[{"type":"string","x-extensible-enum":["roughDraft","inProgress","readyForReview","verified"]},{"type":"null"}],"description":"Which default value this is, or null for a value a space admin added. Clients show the translated name of a default value unless `name` is set. New values can be added in later versions; handle unknown values."},"name":{"description":"Name set by a space admin, or null to show the default name.","type":["string","null"]},"color":{"type":"string","enum":["neutral","accent","info","success","warning","danger"],"description":"Color of the status: `neutral`, `accent`, `info`, `success`, `warning` or `danger`."}},"required":["id","builtIn","name","color"],"additionalProperties":false,"description":"A page status."},{"type":"null"}],"description":"Status of a page, or null when it has none or page status is turned off in the space."},"createdAt":{"type":"string","format":"date-time","description":"When the item was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the item last changed in the tree. ISO 8601 timestamp in UTC."},"contentUpdatedAt":{"type":"string","format":"date-time","description":"When the content of the page last changed. ISO 8601 timestamp in UTC."}},"required":["id","number","spaceId","parentId","kind","title","description","width","numberHeadings","mode","published","archived","position","hasChildren","viewRestriction","editRestricted","link","creatorId","contentLanguage","articleType","translationOf","ownerId","status","createdAt","updatedAt","contentUpdatedAt"],"additionalProperties":false,"description":"An item of the page tree."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","parentId":null,"kind":"folder","title":"VPN access for remote staff","description":"","width":"fixed","numberHeadings":false,"mode":"publish","published":true,"archived":false,"position":"a1","hasChildren":false,"viewRestriction":"none","editRestricted":false,"link":null,"creatorId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","ownerId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","contentLanguage":null,"articleType":null,"translationOf":null,"status":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","builtIn":"verified","name":null,"color":"success"},"createdAt":"2026-10-05T08:00:00.000Z","updatedAt":"2026-10-05T08:00:00.000Z","contentUpdatedAt":"2026-10-05T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidConversion`: The item cannot be converted. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidConversion":{"value":{"type":"urn:lunedo:problem:invalidConversion","title":"The item cannot be converted","status":400,"code":"invalidConversion"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`overviewPage`: The overview page of a space stays a page in its space.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"overviewPage":{"value":{"type":"urn:lunedo:problem:overviewPage","title":"The overview page of a space stays a page in its space","status":409,"code":"overviewPage"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/items/{itemId}/copy":{"post":{"operationId":"copies.copy","summary":"Copy an item","description":"Copies a page, a folder or a whiteboard, optionally with everything below it, within its space or into another space of the same organization. Each copy starts from the published version with one version in its history, gets the current version of every attachment, the labels, page properties, options and status, and belongs to the caller. Comments, reactions, watchers, shares and links stay behind. Links between copied pages point to the copies. When people could read the copy who cannot read the source, the copy is refused with `copyChangesAccess` unless the request carries the confirmation of a preview of exactly that change. Copies of up to 20 items finish within the request; larger ones answer with state `queued`, run in the background and notify the caller at the end; a failed copy leaves nothing behind.\n\nRequires the permission `item.view` on the item in `itemId`.","tags":["Pages"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the page, folder or whiteboard.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"Target space. Leave it out to copy within the space."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Parent item at the target, or null for the root of the tree."},"beforeId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Place the copy directly before this sibling."},"afterId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Place the copy directly after this sibling."},"descendants":{"default":false,"description":"Copy the items below as well. Default false: only the item itself.","type":"boolean"},"confirmation":{"description":"The `confirmation` of a preview. Needed when the copy can be read by people who cannot read the source.","type":"string","maxLength":200}},"required":["parentId"],"additionalProperties":false,"description":"Where the copy goes and what it contains."},"example":{"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","parentId":null,"descendants":true}}}},"responses":{"200":{"description":"The copy.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the copy."},"state":{"type":"string","description":"`queued` and `running` while a large copy runs in the background, `done` when the copy exists, `failed` when nothing was created. New values can be added in later versions; handle unknown values.","x-extensible-enum":["queued","running","done","failed"]},"title":{"type":"string","description":"Title of the copied item when the copy started, or an empty string when the caller can no longer read the copy or its source."},"descendants":{"type":"boolean","description":"Whether the items below were copied as well."},"sourceItemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The copied item, or null when it was deleted permanently since."},"targetSpaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The target space, or null when it was deleted permanently since."},"progress":{"type":"object","properties":{"done":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of items copied so far."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of items the copy creates."}},"required":["done","total"],"additionalProperties":false,"description":"Progress of a copy that runs in the background."},"copied":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of items created, once the copy is done."},"hidden":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of items below that were left out because the person copying cannot read them."},"skipped":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of items below that were left out because they cannot be copied: pages never published, meetings and their series."},"item":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the new item."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the new item in the addresses of the app."},"spaceId":{"type":"string","format":"uuid","description":"ID of its space."},"spaceKey":{"type":"string","description":"Key of its space."},"kind":{"type":"string","description":"Kind of the new item. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title of the new item."}},"required":["id","number","spaceId","spaceKey","kind","title"],"additionalProperties":false},{"type":"null"}],"description":"The new item at the top of the copy, or null until the copy is done."},"errorCode":{"description":"Why a copy failed, for example `copyChangesAccess` (access changed after the confirmation), `storageFull`, `copyInterrupted` or `copyFailed`; null otherwise.","type":["string","null"]},"createdAt":{"type":"string","format":"date-time","description":"When the copy started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the copy finished or failed, or null. ISO 8601 timestamp in UTC."}},"required":["id","state","title","descendants","sourceItemId","targetSpaceId","progress","copied","hidden","skipped","item","errorCode","createdAt","finishedAt"],"additionalProperties":false,"description":"A copy of a page, folder or whiteboard."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","state":"done","title":"VPN access","descendants":true,"sourceItemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","targetSpaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","progress":{"done":4,"total":4},"copied":4,"hidden":1,"skipped":0,"item":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a71","number":1071,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"OPS","kind":"page","title":"VPN access"},"errorCode":null,"createdAt":"2026-10-17T09:30:00.000Z","finishedAt":"2026-10-17T09:30:01.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidPlacement`: The place in the page tree is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidPlacement":{"value":{"type":"urn:lunedo:problem:invalidPlacement","title":"The place in the page tree is not valid","status":400,"code":"invalidPlacement"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`copyChangesAccess`: The copy can be read by people who cannot read the source. `knowledgeBaseContent`: A knowledge base holds only articles and categories. `knowledgeBaseMode`: Articles always use publish mode. `knowledgeBasePlacement`: Articles and categories are placed in categories. `neverPublished`: The page has never been published. `notCopyable`: Only pages, folders and whiteboards can be copied. `otherOrganization`: Content stays within its organization.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"copyChangesAccess":{"value":{"type":"urn:lunedo:problem:copyChangesAccess","title":"The copy can be read by people who cannot read the source","status":409,"code":"copyChangesAccess"}},"knowledgeBaseContent":{"value":{"type":"urn:lunedo:problem:knowledgeBaseContent","title":"A knowledge base holds only articles and categories","status":409,"code":"knowledgeBaseContent"}},"knowledgeBaseMode":{"value":{"type":"urn:lunedo:problem:knowledgeBaseMode","title":"Articles always use publish mode","status":409,"code":"knowledgeBaseMode"}},"knowledgeBasePlacement":{"value":{"type":"urn:lunedo:problem:knowledgeBasePlacement","title":"Articles and categories are placed in categories","status":409,"code":"knowledgeBasePlacement"}},"neverPublished":{"value":{"type":"urn:lunedo:problem:neverPublished","title":"The page has never been published","status":409,"code":"neverPublished"}},"notCopyable":{"value":{"type":"urn:lunedo:problem:notCopyable","title":"Only pages, folders and whiteboards can be copied","status":409,"code":"notCopyable"}},"otherOrganization":{"value":{"type":"urn:lunedo:problem:otherOrganization","title":"Content stays within its organization","status":409,"code":"otherOrganization"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}},"507":{"description":"`storageFull`: Storage is almost full.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"storageFull":{"value":{"type":"urn:lunedo:problem:storageFull","title":"Storage is almost full","status":507,"code":"storageFull"}}}}}}}}},"/api/v1/items/{itemId}/copy/preview":{"post":{"operationId":"copies.preview","summary":"Preview a copy","description":"Shows what a copy to the place would contain and who could read it. The copy inherits the view restrictions of its new place and carries no restrictions, shares or links of its own. When people could read the copy who cannot read the source, the answer carries a confirmation to send with the copy. Items below that the caller cannot read are counted in `hidden`, never named. Copies of more than 20 items run in the background. Needs read access to the item and edit permission in the target space; copying out of a confidential space also needs edit permission there. Nothing is changed.\n\nRequires the permission `item.view` on the item in `itemId`.","tags":["Pages"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the page, folder or whiteboard.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"Target space. Leave it out to copy within the space."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Parent item at the target, or null for the root of the tree."},"descendants":{"default":false,"description":"Copy the items below as well. Default false: only the item itself.","type":"boolean"}},"required":["parentId"],"additionalProperties":false,"description":"The place the copy would go to."},"example":{"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","parentId":null,"descendants":true}}}},"responses":{"200":{"description":"What the copy contains and who could read it.","content":{"application/json":{"schema":{"type":"object","properties":{"gaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who get access."},"losing":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who lose access."},"raised":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role rises."},"lowered":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role drops."},"unlisted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of affected people the caller may not see; they are counted but not listed."},"truncated":{"type":"boolean","description":"Whether `changes` lists only the first 100 people."},"changes":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."},"before":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role before the change, or null for no access."},"after":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role after the change, or null for no access."}},"required":["accountId","name","before","after"],"additionalProperties":false,"description":"How the access of one person changes."},"description":"People whose access changes, ordered by name."},"leavesConfidential":{"type":"boolean","description":"True when the copy leaves a confidential space and is not protected by it."},"widerAccess":{"type":"boolean","description":"True when people can read the copy who cannot read the source; the copy then needs the confirmation."},"confirmation":{"description":"Send this with the copy to confirm exactly this access, or null when nobody gains access. Valid for one hour.","type":["string","null"]},"items":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of items the copy creates."},"hidden":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of items below that are left out because the caller cannot read them."},"skipped":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of items below that are left out because they cannot be copied."},"background":{"type":"boolean","description":"True when the copy is large and runs in the background."}},"required":["gaining","losing","raised","lowered","unlisted","truncated","changes","leavesConfidential","widerAccess","confirmation","items","hidden","skipped","background"],"additionalProperties":false,"description":"Who can read the source and the copy: `gaining` counts people who can read the copy but not the source, `losing` people who can read the source but not the copy."},"example":{"gaining":1,"losing":0,"raised":0,"lowered":0,"unlisted":0,"truncated":false,"changes":[{"accountId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger","before":null,"after":"reader"}],"leavesConfidential":false,"widerAccess":true,"confirmation":"mbx2k1c0.Hq3l2bS8yq1m0e7pW9cJx4rT6uV5aZ2nD0gF1hK8sLw","items":4,"hidden":1,"skipped":0,"background":false}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidPlacement`: The place in the page tree is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidPlacement":{"value":{"type":"urn:lunedo:problem:invalidPlacement","title":"The place in the page tree is not valid","status":400,"code":"invalidPlacement"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`knowledgeBaseContent`: A knowledge base holds only articles and categories. `knowledgeBaseMode`: Articles always use publish mode. `knowledgeBasePlacement`: Articles and categories are placed in categories. `neverPublished`: The page has never been published. `notCopyable`: Only pages, folders and whiteboards can be copied. `otherOrganization`: Content stays within its organization.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"knowledgeBaseContent":{"value":{"type":"urn:lunedo:problem:knowledgeBaseContent","title":"A knowledge base holds only articles and categories","status":409,"code":"knowledgeBaseContent"}},"knowledgeBaseMode":{"value":{"type":"urn:lunedo:problem:knowledgeBaseMode","title":"Articles always use publish mode","status":409,"code":"knowledgeBaseMode"}},"knowledgeBasePlacement":{"value":{"type":"urn:lunedo:problem:knowledgeBasePlacement","title":"Articles and categories are placed in categories","status":409,"code":"knowledgeBasePlacement"}},"neverPublished":{"value":{"type":"urn:lunedo:problem:neverPublished","title":"The page has never been published","status":409,"code":"neverPublished"}},"notCopyable":{"value":{"type":"urn:lunedo:problem:notCopyable","title":"Only pages, folders and whiteboards can be copied","status":409,"code":"notCopyable"}},"otherOrganization":{"value":{"type":"urn:lunedo:problem:otherOrganization","title":"Content stays within its organization","status":409,"code":"otherOrganization"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/items/{itemId}/move":{"post":{"operationId":"items.move","summary":"Move an item","description":"Moves an item with its children to another place, also in another space. Moving below the item itself or one of its descendants is refused. Moving to another space needs edit permission in both spaces, stays within the organization, never involves a personal space and is refused while pages below are restricted so that the caller cannot open or edit them. When the move changes who can access the content, through roles or inherited view restrictions, it is refused with the change unless the request carries the confirmation of a preview of exactly that change.\n\nRequires the permission `item.edit` on the item in `itemId`.","tags":["Pages"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the page, folder or link.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"Target space. Leave it out to stay in the space."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Parent item, or null for the root of the tree."},"beforeId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Place the item directly before this sibling."},"afterId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Place the item directly after this sibling. Without either, the item goes last."},"confirmation":{"description":"Confirmation from the preview of this move. Needed when the move changes who can access the content.","type":"string","maxLength":200}},"required":["parentId"],"additionalProperties":false,"description":"Where the item goes. Moving to another space needs edit permission in both spaces."},"example":{"parentId":null,"afterId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a41"}}}},"responses":{"200":{"description":"The moved item.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the item."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app, unique in the instance. It never changes and is never reused."},"spaceId":{"type":"string","format":"uuid","description":"Space of the item."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Parent item, or null at the root of the tree."},"kind":{"type":"string","description":"`page`, `folder`, `link`, `blogPost`, `meetingSeries`, `meetingTopic` or `whiteboard`. Blog posts and topics are not part of the tree; they appear in the blog and the meetings of their space. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title. Empty for a link to content the caller cannot read."},"description":{"type":"string","description":"Short description of a folder."},"width":{"type":"string","enum":["fixed","full"],"description":"Page width: `fixed` or `full`."},"numberHeadings":{"type":"boolean","description":"Whether the headings of the page are numbered in the page, in print and in Word."},"mode":{"type":"string","enum":["publish","live"],"description":"Editing mode of a page: `publish` (readers see the last published version while editors work on a draft) or `live` (readers see every change at once). Folders and links are always `live`."},"published":{"type":"boolean","description":"Whether readers can see the page. False for a page in publish mode that was never published; only editors see it."},"archived":{"type":"boolean","description":"Whether the item is archived. Archived items are read-only."},"position":{"type":"string","description":"Sort key among the siblings. Items sort by it in binary order."},"hasChildren":{"type":"boolean","description":"Whether the item has children."},"viewRestriction":{"type":"string","enum":["none","own","inherited"],"description":"Whether only an access list may view the item: set on the item itself, on a page above, or not at all."},"editRestricted":{"type":"boolean","description":"Whether only an access list may edit the item."},"link":{"anyOf":[{"type":"object","properties":{"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Linked page, folder or whiteboard, or null for an address or when the caller cannot read it."},"url":{"description":"Linked `http` or `https` address, or null.","type":["string","null"]},"accessible":{"type":"boolean","description":"Whether the caller can open the target. If not, the title is empty."},"inTrash":{"type":"boolean","description":"Whether the target is in the trash. Only true for callers who could read it before."},"target":{"anyOf":[{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"Space of the target."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the target in the addresses of the app."},"spaceKey":{"type":"string","description":"Key of that space."},"kind":{"type":"string","description":"Kind of the target. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title of the target."}},"required":["spaceId","number","spaceKey","kind","title"],"additionalProperties":false},{"type":"null"}],"description":"The linked page, folder or whiteboard, or null."}},"required":["itemId","url","accessible","inTrash","target"],"additionalProperties":false,"description":"Where a link in the page tree points."},{"type":"null"}],"description":"Target of a link, or null for pages and folders."},"creatorId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Account that created the item, or null."},"contentLanguage":{"anyOf":[{"type":"string","description":"Content language as an ISO 639-1 code, or `other` for a language without its own word matching. Words are then matched as written. New values can be added in later versions; handle unknown values.","x-extensible-enum":["ar","ca","da","de","el","en","es","eu","fi","fr","ga","hi","hu","hy","id","it","lt","nb","ne","nl","pt","ro","ru","sr","sv","ta","tr","yi","other"]},{"type":"null"}],"description":"Language of the page content for search, or null to use the language of the space."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Type of an article in a knowledge base, or null for other items and articles without a type."},"translationOf":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Original article of a translation in a knowledge base, or null. A translation is listed below its original; `contentLanguage` is its language."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of the item, or null. The owner stays set when the person leaves; `owner.active` in the item details says whether the item has an active owner."},"status":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the status value."},"builtIn":{"anyOf":[{"type":"string","x-extensible-enum":["roughDraft","inProgress","readyForReview","verified"]},{"type":"null"}],"description":"Which default value this is, or null for a value a space admin added. Clients show the translated name of a default value unless `name` is set. New values can be added in later versions; handle unknown values."},"name":{"description":"Name set by a space admin, or null to show the default name.","type":["string","null"]},"color":{"type":"string","enum":["neutral","accent","info","success","warning","danger"],"description":"Color of the status: `neutral`, `accent`, `info`, `success`, `warning` or `danger`."}},"required":["id","builtIn","name","color"],"additionalProperties":false,"description":"A page status."},{"type":"null"}],"description":"Status of a page, or null when it has none or page status is turned off in the space."},"createdAt":{"type":"string","format":"date-time","description":"When the item was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the item last changed in the tree. ISO 8601 timestamp in UTC."},"contentUpdatedAt":{"type":"string","format":"date-time","description":"When the content of the page last changed. ISO 8601 timestamp in UTC."}},"required":["id","number","spaceId","parentId","kind","title","description","width","numberHeadings","mode","published","archived","position","hasChildren","viewRestriction","editRestricted","link","creatorId","contentLanguage","articleType","translationOf","ownerId","status","createdAt","updatedAt","contentUpdatedAt"],"additionalProperties":false,"description":"An item of the page tree."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","parentId":null,"kind":"page","title":"VPN access for remote staff","description":"","width":"fixed","numberHeadings":false,"mode":"publish","published":true,"archived":false,"position":"a1","hasChildren":false,"viewRestriction":"none","editRestricted":false,"link":null,"creatorId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","ownerId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","contentLanguage":null,"articleType":null,"translationOf":null,"status":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","builtIn":"verified","name":null,"color":"success"},"createdAt":"2026-10-05T08:00:00.000Z","updatedAt":"2026-10-05T08:00:00.000Z","contentUpdatedAt":"2026-10-05T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidPlacement`: The place in the page tree is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidPlacement":{"value":{"type":"urn:lunedo:problem:invalidPlacement","title":"The place in the page tree is not valid","status":400,"code":"invalidPlacement"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`confidentialGuestsBySpaceAdmins`: Only space administrators give guests access to a confidential space. `csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"confidentialGuestsBySpaceAdmins":{"value":{"type":"urn:lunedo:problem:confidentialGuestsBySpaceAdmins","title":"Only space administrators give guests access to a confidential space","status":403,"code":"confidentialGuestsBySpaceAdmins"}},"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`confidentialSharing`: The content is shared too broadly for a confidential space. `hiddenContent`: Pages below are restricted so that the caller cannot open or edit them. `itemMoved`: The item was moved at the same moment. `knowledgeBaseContent`: A knowledge base holds only articles and categories. `knowledgeBaseMode`: Articles always use publish mode. `knowledgeBasePlacement`: Articles and categories are placed in categories. `moveChangesAccess`: The move changes who can access the content. `moveIntoDescendant`: An item cannot be moved below itself. `otherOrganization`: Content stays within its organization. `overviewPage`: The overview page of a space stays a page in its space.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"confidentialSharing":{"value":{"type":"urn:lunedo:problem:confidentialSharing","title":"The content is shared too broadly for a confidential space","status":409,"code":"confidentialSharing"}},"hiddenContent":{"value":{"type":"urn:lunedo:problem:hiddenContent","title":"Pages below are restricted so that the caller cannot open or edit them","status":409,"code":"hiddenContent"}},"itemMoved":{"value":{"type":"urn:lunedo:problem:itemMoved","title":"The item was moved at the same moment","status":409,"code":"itemMoved"}},"knowledgeBaseContent":{"value":{"type":"urn:lunedo:problem:knowledgeBaseContent","title":"A knowledge base holds only articles and categories","status":409,"code":"knowledgeBaseContent"}},"knowledgeBaseMode":{"value":{"type":"urn:lunedo:problem:knowledgeBaseMode","title":"Articles always use publish mode","status":409,"code":"knowledgeBaseMode"}},"knowledgeBasePlacement":{"value":{"type":"urn:lunedo:problem:knowledgeBasePlacement","title":"Articles and categories are placed in categories","status":409,"code":"knowledgeBasePlacement"}},"moveChangesAccess":{"value":{"type":"urn:lunedo:problem:moveChangesAccess","title":"The move changes who can access the content","status":409,"code":"moveChangesAccess"}},"moveIntoDescendant":{"value":{"type":"urn:lunedo:problem:moveIntoDescendant","title":"An item cannot be moved below itself","status":409,"code":"moveIntoDescendant"}},"otherOrganization":{"value":{"type":"urn:lunedo:problem:otherOrganization","title":"Content stays within its organization","status":409,"code":"otherOrganization"}},"overviewPage":{"value":{"type":"urn:lunedo:problem:overviewPage","title":"The overview page of a space stays a page in its space","status":409,"code":"overviewPage"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/items/{itemId}/move/preview":{"post":{"operationId":"items.previewMove","summary":"Preview a move","description":"Shows who would gain or lose access to the item and its children if it moved to the place, through roles in the space and through view restrictions it inherits there. When access changes, the answer carries a confirmation to send with the move. Needs edit permission in both spaces. Moving into a space of another organization or into or out of a personal space is refused, and so is moving to another space while pages below are restricted so that the caller cannot open or edit them. Nothing is changed.\n\nRequires the permission `item.edit` on the item in `itemId`.","tags":["Pages"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the page, folder or link.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"Target space. Leave it out to stay in the space."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Parent item, or null for the root of the tree."}},"required":["parentId"],"additionalProperties":false,"description":"The place the item would move to."},"example":{"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","parentId":null}}}},"responses":{"200":{"description":"The change in access.","content":{"application/json":{"schema":{"type":"object","properties":{"gaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who get access."},"losing":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who lose access."},"raised":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role rises."},"lowered":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role drops."},"unlisted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of affected people the caller may not see; they are counted but not listed."},"truncated":{"type":"boolean","description":"Whether `changes` lists only the first 100 people."},"changes":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."},"before":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role before the change, or null for no access."},"after":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role after the change, or null for no access."}},"required":["accountId","name","before","after"],"additionalProperties":false,"description":"How the access of one person changes."},"description":"People whose access changes, ordered by name."},"leavesConfidential":{"type":"boolean","description":"True when the content leaves a confidential space and loses its protection."},"confirmation":{"description":"Send this with the move to confirm exactly this change, or null when access does not change. Valid for one hour.","type":["string","null"]}},"required":["gaining","losing","raised","lowered","unlisted","truncated","changes","leavesConfidential","confirmation"],"additionalProperties":false,"description":"Who gains, loses or changes access through the move."},"example":{"gaining":1,"losing":0,"raised":0,"lowered":0,"unlisted":0,"truncated":false,"changes":[{"accountId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger","before":null,"after":"reader"}],"leavesConfidential":false,"confirmation":"mbx2k1c0.Hq3l2bS8yq1m0e7pW9cJx4rT6uV5aZ2nD0gF1hK8sLw"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidPlacement`: The place in the page tree is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidPlacement":{"value":{"type":"urn:lunedo:problem:invalidPlacement","title":"The place in the page tree is not valid","status":400,"code":"invalidPlacement"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`confidentialSharing`: The content is shared too broadly for a confidential space. `hiddenContent`: Pages below are restricted so that the caller cannot open or edit them. `knowledgeBaseContent`: A knowledge base holds only articles and categories. `knowledgeBaseMode`: Articles always use publish mode. `knowledgeBasePlacement`: Articles and categories are placed in categories. `moveIntoDescendant`: An item cannot be moved below itself. `otherOrganization`: Content stays within its organization. `overviewPage`: The overview page of a space stays a page in its space.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"confidentialSharing":{"value":{"type":"urn:lunedo:problem:confidentialSharing","title":"The content is shared too broadly for a confidential space","status":409,"code":"confidentialSharing"}},"hiddenContent":{"value":{"type":"urn:lunedo:problem:hiddenContent","title":"Pages below are restricted so that the caller cannot open or edit them","status":409,"code":"hiddenContent"}},"knowledgeBaseContent":{"value":{"type":"urn:lunedo:problem:knowledgeBaseContent","title":"A knowledge base holds only articles and categories","status":409,"code":"knowledgeBaseContent"}},"knowledgeBaseMode":{"value":{"type":"urn:lunedo:problem:knowledgeBaseMode","title":"Articles always use publish mode","status":409,"code":"knowledgeBaseMode"}},"knowledgeBasePlacement":{"value":{"type":"urn:lunedo:problem:knowledgeBasePlacement","title":"Articles and categories are placed in categories","status":409,"code":"knowledgeBasePlacement"}},"moveIntoDescendant":{"value":{"type":"urn:lunedo:problem:moveIntoDescendant","title":"An item cannot be moved below itself","status":409,"code":"moveIntoDescendant"}},"otherOrganization":{"value":{"type":"urn:lunedo:problem:otherOrganization","title":"Content stays within its organization","status":409,"code":"otherOrganization"}},"overviewPage":{"value":{"type":"urn:lunedo:problem:overviewPage","title":"The overview page of a space stays a page in its space","status":409,"code":"overviewPage"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/items/{itemId}/owner":{"put":{"operationId":"ownership.transfer","summary":"Give an item a new owner","description":"Makes the person the owner of the item. The owner, space admins and, outside confidential spaces, organization admins who can read the space may do this. The new owner needs edit access to the item. Archived items, items in the trash and meeting topics keep their owner.\n\nRequires the permission `item.transferOwnership` on the item in `itemId`.","tags":["Ownership and status"],"x-lunedo-permission":{"action":"item.transferOwnership","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the page, folder, link, blog post or meeting series.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ownerId":{"type":"string","format":"uuid","description":"The new owner. The person needs edit access to the item."}},"required":["ownerId"],"additionalProperties":false,"description":"The new owner."},"example":{"ownerId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20"}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `ownerNeedsEditAccess`: The new owner cannot edit the item.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"ownerNeedsEditAccess":{"value":{"type":"urn:lunedo:problem:ownerNeedsEditAccess","title":"The new owner cannot edit the item","status":400,"code":"ownerNeedsEditAccess"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`ownershipNotTransferable`: The owner of this item cannot be changed here.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ownershipNotTransferable":{"value":{"type":"urn:lunedo:problem:ownershipNotTransferable","title":"The owner of this item cannot be changed here","status":409,"code":"ownershipNotTransferable"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/items/{itemId}/owner-candidates":{"get":{"operationId":"ownership.candidates","summary":"Find people who can become the owner","description":"Lists active people the caller can see who have edit access to the item now, by name. The current owner is left out.\n\nRequires the permission `item.transferOwnership` on the item in `itemId`.","tags":["Ownership and status"],"x-lunedo-permission":{"action":"item.transferOwnership","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the page, folder, link, blog post or meeting series.","schema":{"type":"string","format":"uuid"}},{"name":"q","in":"query","required":false,"description":"Part of the name or e-mail address.","schema":{"default":"","type":"string","maxLength":200}}],"responses":{"200":{"description":"Up to 20 people.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the person."},"name":{"type":"string","description":"Name of the person."},"email":{"description":"E-mail address, or null when the caller may not see it.","type":["string","null"]}},"required":["id","name","email"],"additionalProperties":false,"description":"A person who can become the owner."},"description":"The people."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Weber","email":"anna.weber@example.org"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/items/{itemId}/status":{"put":{"operationId":"ownership.setStatus","summary":"Set or remove the status of a page","description":"Sets the status of a page to a value of its space, or removes it. The status is not part of the content or its versions; the change appears in the page's activity.\n\nRequires the permission `item.edit` on the item in `itemId`.","tags":["Ownership and status"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the page, folder, link, blog post or meeting series.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"statusId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"A status value of the item's space, or null to remove the status."}},"required":["statusId"],"additionalProperties":false,"description":"The new status."},"example":{"statusId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60"}}}},"responses":{"200":{"description":"The status now, or null.","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the status value."},"builtIn":{"anyOf":[{"type":"string","x-extensible-enum":["roughDraft","inProgress","readyForReview","verified"]},{"type":"null"}],"description":"Which default value this is, or null for a value a space admin added. Clients show the translated name of a default value unless `name` is set. New values can be added in later versions; handle unknown values."},"name":{"description":"Name set by a space admin, or null to show the default name.","type":["string","null"]},"color":{"type":"string","enum":["neutral","accent","info","success","warning","danger"],"description":"Color of the status: `neutral`, `accent`, `info`, `success`, `warning` or `danger`."}},"required":["id","builtIn","name","color"],"additionalProperties":false,"description":"A page status."},{"type":"null"}],"description":"The status, or null."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","builtIn":"verified","name":null,"color":"success"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidStatus`: The status is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidStatus":{"value":{"type":"urn:lunedo:problem:invalidStatus","title":"The status is not valid","status":400,"code":"invalidStatus"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `statusNotFound`: The status does not exist anymore.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"statusNotFound":{"value":{"type":"urn:lunedo:problem:statusNotFound","title":"The status does not exist anymore","status":404,"code":"statusNotFound"}}}}}},"409":{"description":"`statusDisabled`: Page status is turned off in this space.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"statusDisabled":{"value":{"type":"urn:lunedo:problem:statusDisabled","title":"Page status is turned off in this space","status":409,"code":"statusDisabled"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/items/{itemId}/unarchive":{"post":{"operationId":"items.unarchive","summary":"Bring back an archived item","description":"Returns an archived page or folder with its descendants to its old place in the page tree, or to the top level when that place no longer exists. When the former parent page is in the trash and the item would lose a view restriction it inherited, the request is refused with `restrictedParentInTrash`; repeat it with `withParents=true` to restore the parent pages from the trash with it.\n\nRequires the permission `item.archive` on the item in `itemId`.","tags":["Pages"],"x-lunedo-permission":{"action":"item.archive","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the page, folder or link.","schema":{"type":"string","format":"uuid"}},{"name":"withParents","in":"query","required":false,"description":"`true` also restores the former parent pages from the trash when the content would otherwise lose a view restriction it inherited. It needs the right to restore each of them.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"Where the item went.","content":{"application/json":{"schema":{"type":"object","properties":{"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The new parent, or null for the top level."},"parentEntries":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of trash entries of former parent pages restored with it, so it keeps the view restrictions it inherited."}},"required":["parentId","parentEntries"],"additionalProperties":false,"description":"The place of the item."},"example":{"parentId":null,"parentEntries":0}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notArchived`: The item is not archived. `restrictedParentInTrash`: The content was below a restricted page that is in the trash.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notArchived":{"value":{"type":"urn:lunedo:problem:notArchived","title":"The item is not archived","status":409,"code":"notArchived"}},"restrictedParentInTrash":{"value":{"type":"urn:lunedo:problem:restrictedParentInTrash","title":"The content was below a restricted page that is in the trash","status":409,"code":"restrictedParentInTrash"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/items/{itemId}/views":{"post":{"operationId":"home.view","summary":"Record a view","description":"Adds the item to the caller's recently viewed items. Views older than 90 days are deleted.\n\nRequires the permission `item.view` on the item in `itemId`.","tags":["Home"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the page or blog post.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/items/{itemId}/watch":{"delete":{"operationId":"watches.resetItem","summary":"Remove the watch state of an item","description":"The item then follows its meeting series and its space again.\n\nRequires the permission `item.view` on the item in `itemId`.","tags":["Watching"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the page, blog post, meeting series or meeting topic.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The watch state that applies now.","content":{"application/json":{"schema":{"type":"object","properties":{"own":{"anyOf":[{"type":"object","properties":{"state":{"type":"string","enum":["watching","muted","notWatching"],"description":"`watching` delivers changes and comments, `muted` silences everything from it, `notWatching` stops watching it even when its space or meeting series is watched."},"keepActionable":{"type":"boolean","description":"Whether mentions, assigned tasks, shares with the person and access requests they can decide still arrive while muted."},"automatic":{"type":"boolean","description":"True when the caller watches because they created, edited or commented on it."}},"required":["state","keepActionable","automatic"],"additionalProperties":false},{"type":"null"}],"description":"The state the caller set for this item or space, or null."},"effective":{"anyOf":[{"type":"object","properties":{"state":{"type":"string","enum":["watching","muted","notWatching"],"description":"`watching` delivers changes and comments, `muted` silences everything from it, `notWatching` stops watching it even when its space or meeting series is watched."},"keepActionable":{"type":"boolean","description":"Whether mentions, assigned tasks, shares with the person and access requests they can decide still arrive while muted."},"source":{"type":"string","enum":["target","series","space"],"description":"Where the state comes from: the item or space itself, its meeting series or its space."}},"required":["state","keepActionable","source"],"additionalProperties":false},{"type":"null"}],"description":"The state that applies, or null when nothing is set."}},"required":["own","effective"],"additionalProperties":false,"description":"Whether the caller watches or muted the item or space."},"example":{"own":null,"effective":{"state":"watching","keepActionable":true,"source":"space"}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"get":{"operationId":"watches.itemStatus","summary":"Get the watch state of an item","description":"Shows the state the caller set for the item and the state that applies, which can come from the item's meeting series or space.\n\nRequires the permission `item.view` on the item in `itemId`.","tags":["Watching"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the page, blog post, meeting series or meeting topic.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The caller's watch state.","content":{"application/json":{"schema":{"type":"object","properties":{"own":{"anyOf":[{"type":"object","properties":{"state":{"type":"string","enum":["watching","muted","notWatching"],"description":"`watching` delivers changes and comments, `muted` silences everything from it, `notWatching` stops watching it even when its space or meeting series is watched."},"keepActionable":{"type":"boolean","description":"Whether mentions, assigned tasks, shares with the person and access requests they can decide still arrive while muted."},"automatic":{"type":"boolean","description":"True when the caller watches because they created, edited or commented on it."}},"required":["state","keepActionable","automatic"],"additionalProperties":false},{"type":"null"}],"description":"The state the caller set for this item or space, or null."},"effective":{"anyOf":[{"type":"object","properties":{"state":{"type":"string","enum":["watching","muted","notWatching"],"description":"`watching` delivers changes and comments, `muted` silences everything from it, `notWatching` stops watching it even when its space or meeting series is watched."},"keepActionable":{"type":"boolean","description":"Whether mentions, assigned tasks, shares with the person and access requests they can decide still arrive while muted."},"source":{"type":"string","enum":["target","series","space"],"description":"Where the state comes from: the item or space itself, its meeting series or its space."}},"required":["state","keepActionable","source"],"additionalProperties":false},{"type":"null"}],"description":"The state that applies, or null when nothing is set."}},"required":["own","effective"],"additionalProperties":false,"description":"Whether the caller watches or muted the item or space."},"example":{"own":null,"effective":{"state":"watching","keepActionable":true,"source":"space"}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"put":{"operationId":"watches.watchItem","summary":"Watch, mute or stop watching an item","description":"Watching never grants access: while the caller cannot read the item, nothing is delivered, and delivery resumes when access returns.\n\nRequires the permission `item.view` on the item in `itemId`.","tags":["Watching"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the page, blog post, meeting series or meeting topic.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"state":{"type":"string","enum":["watching","muted","notWatching"],"description":"`watching` delivers changes and comments, `muted` silences everything from it, `notWatching` stops watching it even when its space or meeting series is watched."},"keepActionable":{"description":"For `muted`: still deliver mentions, assigned tasks, shares with the caller and access requests the caller can decide. Default true.","type":"boolean"}},"required":["state"],"additionalProperties":false,"description":"The new state."},"example":{"state":"muted","keepActionable":true}}}},"responses":{"200":{"description":"The new watch state.","content":{"application/json":{"schema":{"type":"object","properties":{"own":{"anyOf":[{"type":"object","properties":{"state":{"type":"string","enum":["watching","muted","notWatching"],"description":"`watching` delivers changes and comments, `muted` silences everything from it, `notWatching` stops watching it even when its space or meeting series is watched."},"keepActionable":{"type":"boolean","description":"Whether mentions, assigned tasks, shares with the person and access requests they can decide still arrive while muted."},"automatic":{"type":"boolean","description":"True when the caller watches because they created, edited or commented on it."}},"required":["state","keepActionable","automatic"],"additionalProperties":false},{"type":"null"}],"description":"The state the caller set for this item or space, or null."},"effective":{"anyOf":[{"type":"object","properties":{"state":{"type":"string","enum":["watching","muted","notWatching"],"description":"`watching` delivers changes and comments, `muted` silences everything from it, `notWatching` stops watching it even when its space or meeting series is watched."},"keepActionable":{"type":"boolean","description":"Whether mentions, assigned tasks, shares with the person and access requests they can decide still arrive while muted."},"source":{"type":"string","enum":["target","series","space"],"description":"Where the state comes from: the item or space itself, its meeting series or its space."}},"required":["state","keepActionable","source"],"additionalProperties":false},{"type":"null"}],"description":"The state that applies, or null when nothing is set."}},"required":["own","effective"],"additionalProperties":false,"description":"Whether the caller watches or muted the item or space."},"example":{"own":null,"effective":{"state":"watching","keepActionable":true,"source":"space"}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/items/by-number/{number}":{"get":{"operationId":"items.getByNumber","summary":"Get an item by its number","description":"Returns the same item as `GET /items/{itemId}`, found by the number in its address in the app. A number that does not exist and a number of an item the caller cannot see give the same `notFound` answer.\n\nRequires the permission `item.view` on the item in `number`.","tags":["Pages"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"number"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"number","in":"path","required":true,"description":"Number of the item, as shown in the addresses of the app.","schema":{"type":"string","pattern":"^[1-9][0-9]{0,14}$"}}],"responses":{"200":{"description":"The item.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the item."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app, unique in the instance. It never changes and is never reused."},"spaceId":{"type":"string","format":"uuid","description":"Space of the item."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Parent item, or null at the root of the tree."},"kind":{"type":"string","description":"`page`, `folder`, `link`, `blogPost`, `meetingSeries`, `meetingTopic` or `whiteboard`. Blog posts and topics are not part of the tree; they appear in the blog and the meetings of their space. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title. Empty for a link to content the caller cannot read."},"description":{"type":"string","description":"Short description of a folder."},"width":{"type":"string","enum":["fixed","full"],"description":"Page width: `fixed` or `full`."},"numberHeadings":{"type":"boolean","description":"Whether the headings of the page are numbered in the page, in print and in Word."},"mode":{"type":"string","enum":["publish","live"],"description":"Editing mode of a page: `publish` (readers see the last published version while editors work on a draft) or `live` (readers see every change at once). Folders and links are always `live`."},"published":{"type":"boolean","description":"Whether readers can see the page. False for a page in publish mode that was never published; only editors see it."},"archived":{"type":"boolean","description":"Whether the item is archived. Archived items are read-only."},"position":{"type":"string","description":"Sort key among the siblings. Items sort by it in binary order."},"hasChildren":{"type":"boolean","description":"Whether the item has children."},"viewRestriction":{"type":"string","enum":["none","own","inherited"],"description":"Whether only an access list may view the item: set on the item itself, on a page above, or not at all."},"editRestricted":{"type":"boolean","description":"Whether only an access list may edit the item."},"link":{"anyOf":[{"type":"object","properties":{"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Linked page, folder or whiteboard, or null for an address or when the caller cannot read it."},"url":{"description":"Linked `http` or `https` address, or null.","type":["string","null"]},"accessible":{"type":"boolean","description":"Whether the caller can open the target. If not, the title is empty."},"inTrash":{"type":"boolean","description":"Whether the target is in the trash. Only true for callers who could read it before."},"target":{"anyOf":[{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"Space of the target."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the target in the addresses of the app."},"spaceKey":{"type":"string","description":"Key of that space."},"kind":{"type":"string","description":"Kind of the target. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title of the target."}},"required":["spaceId","number","spaceKey","kind","title"],"additionalProperties":false},{"type":"null"}],"description":"The linked page, folder or whiteboard, or null."}},"required":["itemId","url","accessible","inTrash","target"],"additionalProperties":false,"description":"Where a link in the page tree points."},{"type":"null"}],"description":"Target of a link, or null for pages and folders."},"creatorId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Account that created the item, or null."},"contentLanguage":{"anyOf":[{"type":"string","description":"Content language as an ISO 639-1 code, or `other` for a language without its own word matching. Words are then matched as written. New values can be added in later versions; handle unknown values.","x-extensible-enum":["ar","ca","da","de","el","en","es","eu","fi","fr","ga","hi","hu","hy","id","it","lt","nb","ne","nl","pt","ro","ru","sr","sv","ta","tr","yi","other"]},{"type":"null"}],"description":"Language of the page content for search, or null to use the language of the space."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Type of an article in a knowledge base, or null for other items and articles without a type."},"translationOf":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Original article of a translation in a knowledge base, or null. A translation is listed below its original; `contentLanguage` is its language."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of the item, or null. The owner stays set when the person leaves; `owner.active` in the item details says whether the item has an active owner."},"status":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the status value."},"builtIn":{"anyOf":[{"type":"string","x-extensible-enum":["roughDraft","inProgress","readyForReview","verified"]},{"type":"null"}],"description":"Which default value this is, or null for a value a space admin added. Clients show the translated name of a default value unless `name` is set. New values can be added in later versions; handle unknown values."},"name":{"description":"Name set by a space admin, or null to show the default name.","type":["string","null"]},"color":{"type":"string","enum":["neutral","accent","info","success","warning","danger"],"description":"Color of the status: `neutral`, `accent`, `info`, `success`, `warning` or `danger`."}},"required":["id","builtIn","name","color"],"additionalProperties":false,"description":"A page status."},{"type":"null"}],"description":"Status of a page, or null when it has none or page status is turned off in the space."},"createdAt":{"type":"string","format":"date-time","description":"When the item was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the item last changed in the tree. ISO 8601 timestamp in UTC."},"contentUpdatedAt":{"type":"string","format":"date-time","description":"When the content of the page last changed. ISO 8601 timestamp in UTC."},"spaceKey":{"type":"string","description":"Key of the space. Empty when the caller sees the item only through a share or link."},"spaceName":{"type":"string","description":"Name of the space. Empty when the caller sees the item only through a share or link."},"spaceAccess":{"type":"boolean","description":"Whether the caller has access to the space; false when the item is visible only through a share or link."},"spaceContentLanguage":{"type":"string","description":"Content language of the space, which pages without a content language of their own use for search.","x-extensible-enum":["ar","ca","da","de","el","en","es","eu","fi","fr","ga","hi","hu","hy","id","it","lt","nb","ne","nl","pt","ro","ru","sr","sv","ta","tr","yi","other"]},"ancestors":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the ancestor."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the ancestor in the addresses of the app."},"kind":{"type":"string","description":"Kind of the ancestor. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title of the ancestor."},"published":{"type":"boolean","description":"Whether the ancestor counts as published: a folder, a link, a page in live mode or a page with a published version. Readers see a page only when every ancestor is published."}},"required":["id","number","kind","title","published"],"additionalProperties":false,"description":"An ancestor."},"description":"Ancestors from the root down to the parent."},"owner":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the owner."},"name":{"description":"Name of the owner, or null when the caller may not see the person.","type":["string","null"]},"jobTitle":{"description":"Job title the person entered on their profile, or null.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null without one. Changes whenever the picture changes; load the picture from `GET /api/v1/accounts/{accountId}/picture`.","type":["string","null"]},"email":{"description":"E-mail address of the owner, or null when the caller may not see it.","type":["string","null"]},"active":{"type":"boolean","description":"Whether the owner can still act: false when the account is deactivated or its membership in the organization ended."}},"required":["id","name","jobTitle","pictureRef","email","active"],"additionalProperties":false},{"type":"null"}],"description":"Owner of the item, or null when it has none."},"ownershipTransferable":{"type":"boolean","description":"Whether the caller may give the item a new owner."}},"required":["id","number","spaceId","parentId","kind","title","description","width","numberHeadings","mode","published","archived","position","hasChildren","viewRestriction","editRestricted","link","creatorId","contentLanguage","articleType","translationOf","ownerId","status","createdAt","updatedAt","contentUpdatedAt","spaceKey","spaceName","spaceAccess","spaceContentLanguage","ancestors","owner","ownershipTransferable"],"additionalProperties":false,"description":"An item with its place in the tree."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","parentId":null,"kind":"page","title":"VPN access for remote staff","description":"","width":"fixed","numberHeadings":false,"mode":"publish","published":true,"archived":false,"position":"a1","hasChildren":false,"viewRestriction":"none","editRestricted":false,"link":null,"creatorId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","ownerId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","contentLanguage":null,"articleType":null,"translationOf":null,"status":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","builtIn":"verified","name":null,"color":"success"},"createdAt":"2026-10-05T08:00:00.000Z","updatedAt":"2026-10-05T08:00:00.000Z","contentUpdatedAt":"2026-10-05T08:00:00.000Z","spaceKey":"ITOPS","spaceName":"IT Operations","spaceAccess":true,"spaceContentLanguage":"en","ancestors":[],"owner":null,"ownershipTransferable":false}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/meeting-series/{seriesId}":{"get":{"operationId":"meetings.series","summary":"Get a meeting series","description":"Returns members, schedule, template and the next meeting of a series.\n\nRequires the permission `item.view` on the item in `seriesId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"seriesId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"seriesId","in":"path","required":true,"description":"ID of the meeting series.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The series.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the series."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the series in the addresses of the app."},"spaceId":{"type":"string","format":"uuid","description":"Space of the series."},"title":{"type":"string","description":"Name of the series."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Parent page or folder, or null."},"archived":{"type":"boolean","description":"True when the series has ended: read-only, without a next meeting."},"oneOnOne":{"type":"boolean","description":"True for the series of a one-on-one."},"members":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null without one. Changes whenever the picture changes; load the picture from `GET /api/v1/accounts/{accountId}/picture`.","type":["string","null"]},"active":{"type":"boolean","description":"Whether the person can still take part: false when the account is deactivated, not set up yet or no longer a member of the organization. Always true for people the caller may not see."},"canRead":{"type":"boolean","description":"Whether the person can read the series. Active members without access are shown with a warning."}},"required":["id","name","pictureRef","active","canRead"],"additionalProperties":false,"description":"A member of the series."},"description":"Members in their order."},"schedule":{"type":"object","properties":{"rhythm":{"anyOf":[{"type":"object","properties":{"frequency":{"type":"string","description":"How often the meetings repeat. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays for weekly rhythms.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month for monthly rhythms by date.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"1 to 4 or -1 for monthly rhythms by weekday.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekday":{"description":"Weekday for monthly rhythms by weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"The rhythm of the series."},{"type":"null"}],"description":"The rhythm, or null when the rule cannot be shown as one."},"recurrence":{"description":"The iCalendar recurrence rule (RFC 5545) without `RRULE:`, or null without a fixed rhythm.","type":["string","null"]},"startsOn":{"type":"string","description":"Date of the first meeting."},"startTime":{"type":"string","description":"Local start time."},"timeZone":{"type":"string","description":"Time zone of the series."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Duration in minutes."}},"required":["rhythm","recurrence","startsOn","startTime","timeZone","durationMinutes"],"additionalProperties":false,"description":"The schedule."},"template":{"type":"object","properties":{"id":{"type":"string","description":"Template ID."},"name":{"description":"Name of the template, or null when it was deleted.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"Template of the meeting pages."},"reminder":{"type":"string","description":"When attendees are reminded to add their topics: `off`, or one day, two days or one week before each meeting. New values can be added in later versions; handle unknown values.","x-extensible-enum":["off","oneDay","twoDays","oneWeek"]},"source":{"type":"string","description":"Where the schedule comes from: set here or from a calendar. New values can be added in later versions; handle unknown values.","x-extensible-enum":["manual","calendar"]},"calendarUid":{"description":"Calendar UID when the schedule comes from a calendar.","type":["string","null"]},"upcoming":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the meeting page."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the meeting page in the addresses of the app."},"title":{"type":"string","description":"Title of the meeting page."},"state":{"type":"string","description":"`upcoming` is the next meeting, `closed` and `skipped` are done, `reopened` was closed and is open again. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upcoming","closed","reopened","skipped"]},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start of the meeting, or null when it is not scheduled yet. ISO 8601 timestamp in UTC."},"recurrenceId":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Original start of the occurrence in the rhythm, or null. ISO 8601 timestamp in UTC."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Duration in minutes."},"attendees":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of attendees."},"present":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of attendees marked present."},"extra":{"type":"boolean","description":"True for an additional meeting outside the rhythm."},"next":{"type":"boolean","description":"True for the next meeting of the series: the earliest one that is neither held nor skipped."}},"required":["id","number","title","state","startsAt","recurrenceId","durationMinutes","attendees","present","extra","next"],"additionalProperties":false,"description":"A meeting of a series."},{"type":"null"}],"description":"The next meeting, or null when the series has ended."},"openTopics":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Open running topics the caller can see."},"overview":{"type":"object","properties":{"columns":{"minItems":2,"maxItems":2,"type":"array","items":{"type":"array","items":{"type":"string","description":"A module of the series overview. New values can be added in later versions; handle unknown values.","x-extensible-enum":["topics","tasks","decisions","meetings","attendance","links"]}},"description":"Modules of the left and the right column, from top to bottom."},"hidden":{"type":"array","items":{"type":"string","description":"A module of the series overview. New values can be added in later versions; handle unknown values.","x-extensible-enum":["topics","tasks","decisions","meetings","attendance","links"]},"description":"Modules that are not shown."},"links":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the item."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app."},"title":{"type":"string","description":"Title of the item."},"kind":{"type":"string","description":"Kind of the item, such as `page` or `folder`."},"spaceKey":{"type":"string","description":"Key of its space."}},"required":["id","number","title","kind","spaceKey"],"additionalProperties":false,"description":"A pinned item."},"description":"Pinned items for the Links module that the caller can open, in their order."}},"required":["columns","hidden","links"],"additionalProperties":false,"description":"The overview of the series, the same for all members."},"createdAt":{"type":"string","format":"date-time","description":"When the series was created. ISO 8601 timestamp in UTC."}},"required":["id","number","spaceId","title","parentId","archived","oneOnOne","members","schedule","template","reminder","source","calendarUid","upcoming","openTopics","overview","createdAt"],"additionalProperties":false,"description":"A meeting series."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a00","number":1050,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a00","title":"Jour fixe IT","parentId":null,"archived":false,"oneOnOne":false,"members":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger","pictureRef":null,"active":true,"canRead":true}],"schedule":{"rhythm":{"frequency":"weekly","interval":1,"weekdays":["MO"]},"recurrence":"FREQ=WEEKLY;BYDAY=MO","startsOn":"2026-10-12","startTime":"09:30","timeZone":"Europe/Vienna","durationMinutes":45},"template":{"id":"builtin:team-meeting","name":"Team meeting"},"reminder":"oneDay","source":"manual","calendarUid":null,"upcoming":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a10","number":1051,"title":"Jour fixe IT · 12 Oct 2026","state":"upcoming","startsAt":"2026-10-12T07:30:00.000Z","recurrenceId":"2026-10-12T07:30:00.000Z","durationMinutes":45,"attendees":5,"present":0,"extra":false,"next":true},"openTopics":3,"overview":{"columns":[["topics","tasks"],["meetings","decisions"]],"hidden":["attendance","links"],"links":[]},"createdAt":"2026-10-05T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"patch":{"operationId":"meetings.updateSeries","summary":"Change a meeting series","description":"Changes name, members, template or schedule. A new schedule moves the upcoming meeting to the new rhythm and drops earlier moves and exceptions. New members join the upcoming meeting.\n\nRequires the permission `item.edit` on the item in `seriesId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"seriesId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"seriesId","in":"path","required":true,"description":"ID of the meeting series.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"New name.","type":"string","maxLength":400},"members":{"description":"All members, in order.","maxItems":100,"type":"array","items":{"type":"string","format":"uuid","description":"Account ID."}},"templateId":{"description":"Template for new meetings.","type":"string","maxLength":64},"reminder":{"type":"string","enum":["off","oneDay","twoDays","oneWeek"],"description":"When attendees are reminded to add their topics: `off`, or one day, two days or one week before each meeting."},"schedule":{"description":"New schedule. The upcoming meeting moves to the new rhythm.","type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","enum":["none","daily","weekly","monthly","yearly"],"description":"`none` for no fixed rhythm, otherwise how often the meetings repeat."},"interval":{"default":1,"description":"Every how many days, weeks, months or years. 2 weekly is every two weeks, 3 monthly is quarterly.","type":"integer","minimum":1,"maximum":52},"weekdays":{"description":"For `weekly`: the weekdays of the meetings, at least one.","maxItems":7,"type":"array","items":{"type":"string","enum":["MO","TU","WE","TH","FR","SA","SU"],"description":"Weekday as in iCalendar: `MO` to `SU`."}},"monthDay":{"description":"For `monthly` by date: the day of the month.","type":"integer","minimum":1,"maximum":31},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"For `monthly` by weekday: the weekday, for example `TU`.","type":"string","enum":["MO","TU","WE","TH","FR","SA","SU"]}},"required":["frequency"],"additionalProperties":false,"description":"The rhythm of a series, as the interface offers it."},"startsOn":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Date of the first meeting in the series' time zone, YYYY-MM-DD."},"startTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$","description":"Local start time of the meetings, HH:MM in 24 hours."},"timeZone":{"type":"string","minLength":1,"maxLength":64,"description":"IANA time zone of the series, such as `Europe/Vienna`. Meetings keep their local time across daylight saving changes."},"durationMinutes":{"type":"integer","minimum":5,"maximum":1440,"description":"Duration of each meeting in minutes."}},"required":["rhythm","startsOn","startTime","timeZone","durationMinutes"],"additionalProperties":false}},"additionalProperties":false,"description":"Changes to a meeting series. Fields that are left out stay unchanged."},"example":{"members":["01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20"]}}}},"responses":{"200":{"description":"The series.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the series."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the series in the addresses of the app."},"spaceId":{"type":"string","format":"uuid","description":"Space of the series."},"title":{"type":"string","description":"Name of the series."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Parent page or folder, or null."},"archived":{"type":"boolean","description":"True when the series has ended: read-only, without a next meeting."},"oneOnOne":{"type":"boolean","description":"True for the series of a one-on-one."},"members":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null without one. Changes whenever the picture changes; load the picture from `GET /api/v1/accounts/{accountId}/picture`.","type":["string","null"]},"active":{"type":"boolean","description":"Whether the person can still take part: false when the account is deactivated, not set up yet or no longer a member of the organization. Always true for people the caller may not see."},"canRead":{"type":"boolean","description":"Whether the person can read the series. Active members without access are shown with a warning."}},"required":["id","name","pictureRef","active","canRead"],"additionalProperties":false,"description":"A member of the series."},"description":"Members in their order."},"schedule":{"type":"object","properties":{"rhythm":{"anyOf":[{"type":"object","properties":{"frequency":{"type":"string","description":"How often the meetings repeat. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays for weekly rhythms.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month for monthly rhythms by date.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"1 to 4 or -1 for monthly rhythms by weekday.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekday":{"description":"Weekday for monthly rhythms by weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"The rhythm of the series."},{"type":"null"}],"description":"The rhythm, or null when the rule cannot be shown as one."},"recurrence":{"description":"The iCalendar recurrence rule (RFC 5545) without `RRULE:`, or null without a fixed rhythm.","type":["string","null"]},"startsOn":{"type":"string","description":"Date of the first meeting."},"startTime":{"type":"string","description":"Local start time."},"timeZone":{"type":"string","description":"Time zone of the series."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Duration in minutes."}},"required":["rhythm","recurrence","startsOn","startTime","timeZone","durationMinutes"],"additionalProperties":false,"description":"The schedule."},"template":{"type":"object","properties":{"id":{"type":"string","description":"Template ID."},"name":{"description":"Name of the template, or null when it was deleted.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"Template of the meeting pages."},"reminder":{"type":"string","description":"When attendees are reminded to add their topics: `off`, or one day, two days or one week before each meeting. New values can be added in later versions; handle unknown values.","x-extensible-enum":["off","oneDay","twoDays","oneWeek"]},"source":{"type":"string","description":"Where the schedule comes from: set here or from a calendar. New values can be added in later versions; handle unknown values.","x-extensible-enum":["manual","calendar"]},"calendarUid":{"description":"Calendar UID when the schedule comes from a calendar.","type":["string","null"]},"upcoming":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the meeting page."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the meeting page in the addresses of the app."},"title":{"type":"string","description":"Title of the meeting page."},"state":{"type":"string","description":"`upcoming` is the next meeting, `closed` and `skipped` are done, `reopened` was closed and is open again. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upcoming","closed","reopened","skipped"]},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start of the meeting, or null when it is not scheduled yet. ISO 8601 timestamp in UTC."},"recurrenceId":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Original start of the occurrence in the rhythm, or null. ISO 8601 timestamp in UTC."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Duration in minutes."},"attendees":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of attendees."},"present":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of attendees marked present."},"extra":{"type":"boolean","description":"True for an additional meeting outside the rhythm."},"next":{"type":"boolean","description":"True for the next meeting of the series: the earliest one that is neither held nor skipped."}},"required":["id","number","title","state","startsAt","recurrenceId","durationMinutes","attendees","present","extra","next"],"additionalProperties":false,"description":"A meeting of a series."},{"type":"null"}],"description":"The next meeting, or null when the series has ended."},"openTopics":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Open running topics the caller can see."},"overview":{"type":"object","properties":{"columns":{"minItems":2,"maxItems":2,"type":"array","items":{"type":"array","items":{"type":"string","description":"A module of the series overview. New values can be added in later versions; handle unknown values.","x-extensible-enum":["topics","tasks","decisions","meetings","attendance","links"]}},"description":"Modules of the left and the right column, from top to bottom."},"hidden":{"type":"array","items":{"type":"string","description":"A module of the series overview. New values can be added in later versions; handle unknown values.","x-extensible-enum":["topics","tasks","decisions","meetings","attendance","links"]},"description":"Modules that are not shown."},"links":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the item."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app."},"title":{"type":"string","description":"Title of the item."},"kind":{"type":"string","description":"Kind of the item, such as `page` or `folder`."},"spaceKey":{"type":"string","description":"Key of its space."}},"required":["id","number","title","kind","spaceKey"],"additionalProperties":false,"description":"A pinned item."},"description":"Pinned items for the Links module that the caller can open, in their order."}},"required":["columns","hidden","links"],"additionalProperties":false,"description":"The overview of the series, the same for all members."},"createdAt":{"type":"string","format":"date-time","description":"When the series was created. ISO 8601 timestamp in UTC."}},"required":["id","number","spaceId","title","parentId","archived","oneOnOne","members","schedule","template","reminder","source","calendarUid","upcoming","openTopics","overview","createdAt"],"additionalProperties":false,"description":"A meeting series."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a00","number":1050,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a00","title":"Jour fixe IT","parentId":null,"archived":false,"oneOnOne":false,"members":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger","pictureRef":null,"active":true,"canRead":true}],"schedule":{"rhythm":{"frequency":"weekly","interval":1,"weekdays":["MO"]},"recurrence":"FREQ=WEEKLY;BYDAY=MO","startsOn":"2026-10-12","startTime":"09:30","timeZone":"Europe/Vienna","durationMinutes":45},"template":{"id":"builtin:team-meeting","name":"Team meeting"},"reminder":"oneDay","source":"manual","calendarUid":null,"upcoming":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a10","number":1051,"title":"Jour fixe IT · 12 Oct 2026","state":"upcoming","startsAt":"2026-10-12T07:30:00.000Z","recurrenceId":"2026-10-12T07:30:00.000Z","durationMinutes":45,"attendees":5,"present":0,"extra":false,"next":true},"openTopics":3,"overview":{"columns":[["topics","tasks"],["meetings","decisions"]],"hidden":["attendance","links"],"links":[]},"createdAt":"2026-10-05T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidMember`: The person cannot take part. `invalidRhythm`: The rhythm is not valid. `invalidSchedule`: The schedule is not valid. `invalidTimeZone`: The time zone is not known. `invalidTitle`: The title is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidMember":{"value":{"type":"urn:lunedo:problem:invalidMember","title":"The person cannot take part","status":400,"code":"invalidMember"}},"invalidRhythm":{"value":{"type":"urn:lunedo:problem:invalidRhythm","title":"The rhythm is not valid","status":400,"code":"invalidRhythm"}},"invalidSchedule":{"value":{"type":"urn:lunedo:problem:invalidSchedule","title":"The schedule is not valid","status":400,"code":"invalidSchedule"}},"invalidTimeZone":{"value":{"type":"urn:lunedo:problem:invalidTimeZone","title":"The time zone is not known","status":400,"code":"invalidTimeZone"}},"invalidTitle":{"value":{"type":"urn:lunedo:problem:invalidTitle","title":"The title is not valid","status":400,"code":"invalidTitle"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`seriesEnded`: The meeting series has ended.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"seriesEnded":{"value":{"type":"urn:lunedo:problem:seriesEnded","title":"The meeting series has ended","status":409,"code":"seriesEnded"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/meeting-series/{seriesId}/attendance":{"get":{"operationId":"meetings.attendanceRates","summary":"Get the attendance of the members","description":"Counts per member how often they were present in the last held meetings.\n\nRequires the permission `item.view` on the item in `seriesId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"seriesId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"seriesId","in":"path","required":true,"description":"ID of the meeting series.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Attendance per member.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID of the member."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null without one. Changes whenever the picture changes; load the picture from `GET /api/v1/accounts/{accountId}/picture`.","type":["string","null"]},"present":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Meetings the member was marked present in."},"meetings":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Meetings counted."}},"required":["id","name","pictureRef","present","meetings"],"additionalProperties":false,"description":"Attendance of one member."},"description":"Attendance of the members over the last 10 held meetings the caller can read."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger","pictureRef":null,"present":9,"meetings":10}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/meeting-series/{seriesId}/decisions":{"get":{"operationId":"meetings.decisions","summary":"List the decision log of a series","description":"Lists the decisions recorded in the meetings of a series, newest first, with filters for period, topic and text.\n\nRequires the permission `item.view` on the item in `seriesId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"seriesId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"seriesId","in":"path","required":true,"description":"ID of the meeting series.","schema":{"type":"string","format":"uuid"}},{"name":"from","in":"query","required":false,"description":"Only decisions of meetings at or after this moment. ISO 8601 timestamp; an offset is allowed.","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"description":"Only decisions of meetings before this moment. ISO 8601 timestamp; an offset is allowed.","schema":{"type":"string","format":"date-time"}},{"name":"topicId","in":"query","required":false,"description":"Only decisions of this topic.","schema":{"type":"string","format":"uuid"}},{"name":"text","in":"query","required":false,"description":"Only decisions containing this text.","schema":{"type":"string","maxLength":200}},{"name":"limit","in":"query","required":false,"description":"Maximum number of decisions.","schema":{"default":100,"type":"integer","minimum":1,"maximum":500}}],"responses":{"200":{"description":"The decisions.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Decision ID."},"statement":{"type":"array","items":{"$ref":"#/components/schemas/Schema113ae44d8375"},"description":"The statement as blocks of the editor schema."},"text":{"type":"string","description":"The statement as plain text."},"meeting":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Meeting ID."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the meeting in the addresses of the app."},"title":{"type":"string","description":"Title."},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start of the meeting. ISO 8601 timestamp in UTC."}},"required":["id","number","title","startsAt"],"additionalProperties":false,"description":"The meeting it was recorded in."},"topic":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Topic ID."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the topic in the addresses of the app."},"title":{"type":"string","description":"Title."}},"required":["id","number","title"],"additionalProperties":false},{"type":"null"}],"description":"The topic it closed, if visible."},"recordedAt":{"type":"string","format":"date-time","description":"When the decision was first recorded. ISO 8601 timestamp in UTC."}},"required":["id","statement","text","meeting","topic","recordedAt"],"additionalProperties":false,"description":"A decision."},"description":"Decisions."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6c00","statement":[{"type":"paragraph","content":[{"type":"text","text":"Laptops get BitLocker."}]}],"text":"Laptops get BitLocker.","meeting":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a10","number":1051,"title":"Jour fixe IT · 12 Oct 2026","startsAt":"2026-10-12T07:30:00.000Z"},"topic":null,"recordedAt":"2026-10-12T08:00:00.000Z"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/meeting-series/{seriesId}/ended":{"put":{"operationId":"meetings.end","summary":"End a meeting series or continue it","description":"Ending archives the series with its meetings and topics: read-only and without a next meeting. Continuing brings it back; when its former parent page is in the trash and the series would lose a view restriction it inherited, continuing is refused with `restrictedParentInTrash` until that page is restored.\n\nRequires the permission `item.archive` on the item in `seriesId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.archive","resource":"item","parameter":"seriesId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"seriesId","in":"path","required":true,"description":"ID of the meeting series.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ended":{"type":"boolean","description":"True to end the series, false to continue it."}},"required":["ended"],"additionalProperties":false,"description":"Whether the series has ended."},"example":{"ended":true}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`restrictedParentInTrash`: The content was below a restricted page that is in the trash.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"restrictedParentInTrash":{"value":{"type":"urn:lunedo:problem:restrictedParentInTrash","title":"The content was below a restricted page that is in the trash","status":409,"code":"restrictedParentInTrash"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/meeting-series/{seriesId}/meetings":{"get":{"operationId":"meetings.meetings","summary":"List the meetings of a series","description":"Lists the meetings newest first; a meeting that is not scheduled yet comes first.\n\nRequires the permission `item.view` on the item in `seriesId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"seriesId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"seriesId","in":"path","required":true,"description":"ID of the meeting series.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Cursor from `nextCursor` of the previous page.","schema":{"type":"string","maxLength":200}},{"name":"limit","in":"query","required":false,"description":"Maximum number of meetings.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"The meetings.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the meeting page."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the meeting page in the addresses of the app."},"title":{"type":"string","description":"Title of the meeting page."},"state":{"type":"string","description":"`upcoming` is the next meeting, `closed` and `skipped` are done, `reopened` was closed and is open again. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upcoming","closed","reopened","skipped"]},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start of the meeting, or null when it is not scheduled yet. ISO 8601 timestamp in UTC."},"recurrenceId":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Original start of the occurrence in the rhythm, or null. ISO 8601 timestamp in UTC."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Duration in minutes."},"attendees":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of attendees."},"present":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of attendees marked present."},"extra":{"type":"boolean","description":"True for an additional meeting outside the rhythm."},"next":{"type":"boolean","description":"True for the next meeting of the series: the earliest one that is neither held nor skipped."}},"required":["id","number","title","state","startsAt","recurrenceId","durationMinutes","attendees","present","extra","next"],"additionalProperties":false,"description":"A meeting of a series."},"description":"Meetings."},"nextCursor":{"description":"Cursor for the next page, or null.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"A page of meetings."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a10","number":1051,"title":"Jour fixe IT · 12 Oct 2026","state":"upcoming","startsAt":"2026-10-12T07:30:00.000Z","recurrenceId":"2026-10-12T07:30:00.000Z","durationMinutes":45,"attendees":5,"present":0,"extra":false,"next":true}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"meetings.addExtraMeeting","summary":"Plan an additional meeting","description":"Creates a meeting outside the rhythm. It shows the open topics of the series and does not change the next regular meeting.\n\nRequires the permission `item.edit` on the item in `seriesId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"seriesId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"seriesId","in":"path","required":true,"description":"ID of the meeting series.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"startsAt":{"description":"Start of the additional meeting. ISO 8601 timestamp; an offset is allowed.","type":"string","format":"date-time"}},"required":["startsAt"],"additionalProperties":false,"description":"An additional meeting outside the rhythm. It shows the open topics of the series."},"example":{"startsAt":"2026-10-14T13:00:00.000Z"}}}},"responses":{"201":{"description":"The new meeting.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the meeting page."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the meeting page in the addresses of the app."},"seriesId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The series, or null when the caller cannot read it."},"seriesNumber":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the series in the addresses of the app, or null when the caller cannot read it."},"seriesTitle":{"description":"Name of the series, or null when the caller cannot read it.","type":["string","null"]},"title":{"type":"string","description":"Title of the meeting page."},"state":{"type":"string","description":"`upcoming` is the next meeting, `closed` and `skipped` are done, `reopened` was closed and is open again. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upcoming","closed","reopened","skipped"]},"next":{"type":"boolean","description":"True for the next meeting of the series: the earliest one that is neither held nor skipped."},"current":{"type":"boolean","description":"Whether the meeting is open: upcoming or reopened."},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start, or null when not scheduled yet. ISO 8601 timestamp in UTC."},"recurrenceId":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Original start in the rhythm, or null. ISO 8601 timestamp in UTC."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Duration in minutes."},"timeZone":{"description":"Time zone of the series, or null when the caller cannot read the series.","type":["string","null"]},"closedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the meeting was closed or skipped. ISO 8601 timestamp in UTC."},"closedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, if visible.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who closed it."},"nextMeetingId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The meeting created when this one was closed or skipped, or null when the caller cannot read the series."},"previousMeeting":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the meeting."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the meeting in the addresses of the app."},"title":{"type":"string","description":"Title."},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start. ISO 8601 timestamp in UTC."}},"required":["id","number","title","startsAt"],"additionalProperties":false,"description":"A neighboring meeting."},{"type":"null"}],"description":"The meeting of the series before this one that the caller can read, skipped ones left out."},"followingMeeting":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the meeting."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the meeting in the addresses of the app."},"title":{"type":"string","description":"Title."},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start. ISO 8601 timestamp in UTC."}},"required":["id","number","title","startsAt"],"additionalProperties":false,"description":"A neighboring meeting."},{"type":"null"}],"description":"The meeting of the series after this one that the caller can read, skipped ones left out."},"rhythm":{"description":"Whether the series has a fixed rhythm; without one, closing asks for the next date. Null when the caller cannot read the series.","type":["boolean","null"]},"attendees":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, if visible.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null without one. Changes whenever the picture changes; load the picture from `GET /api/v1/accounts/{accountId}/picture`.","type":["string","null"]},"attendance":{"anyOf":[{"type":"string","x-extensible-enum":["present","excused","absent"]},{"type":"null"}],"description":"Attendance, or null when not recorded. New values can be added in later versions; handle unknown values."},"member":{"description":"Whether the person is a member of the series, or null when the caller cannot read it.","type":["boolean","null"]},"active":{"type":"boolean","description":"Whether the person can still take part: false when the account is deactivated, not set up yet or no longer a member of the organization. Always true for people the caller may not see."},"canRead":{"type":"boolean","description":"Whether the person can read the meeting page."}},"required":["id","name","pictureRef","attendance","member","active","canRead"],"additionalProperties":false,"description":"An attendee."},"description":"Attendees in order."},"extra":{"type":"boolean","description":"True for an additional meeting outside the rhythm."},"guests":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the guest entry."},"name":{"type":"string","description":"Name as entered."},"note":{"description":"Optional note, such as the company.","type":["string","null"]},"attendance":{"anyOf":[{"type":"string","x-extensible-enum":["present","excused","absent"]},{"type":"null"}],"description":"Attendance, or null when not recorded. New values can be added in later versions; handle unknown values."}},"required":["id","name","note","attendance"],"additionalProperties":false,"description":"A person without an account. Guests have no access to anything."},"description":"Guests without an account, in order."},"calendarUid":{"description":"Calendar UID of the meeting when it comes from a calendar.","type":["string","null"]}},"required":["id","number","seriesId","seriesNumber","seriesTitle","title","state","next","current","startsAt","recurrenceId","durationMinutes","timeZone","closedAt","closedBy","nextMeetingId","previousMeeting","followingMeeting","rhythm","attendees","extra","guests","calendarUid"],"additionalProperties":false,"description":"A meeting."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a10","number":1051,"seriesId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a00","seriesNumber":1050,"seriesTitle":"Jour fixe IT","title":"Jour fixe IT · 12 Oct 2026","state":"upcoming","next":true,"current":true,"startsAt":"2026-10-12T07:30:00.000Z","recurrenceId":null,"durationMinutes":45,"timeZone":"Europe/Vienna","closedAt":null,"closedBy":null,"nextMeetingId":null,"previousMeeting":null,"followingMeeting":null,"rhythm":true,"attendees":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger","pictureRef":null,"attendance":"present","member":true,"active":true,"canRead":true}],"extra":true,"guests":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6c00","name":"Martin Huber","note":"Printer service","attendance":null}],"calendarUid":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `tooManyExtraMeetings`: The series has too many additional meetings.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"tooManyExtraMeetings":{"value":{"type":"urn:lunedo:problem:tooManyExtraMeetings","title":"The series has too many additional meetings","status":400,"code":"tooManyExtraMeetings"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`seriesEnded`: The meeting series has ended.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"seriesEnded":{"value":{"type":"urn:lunedo:problem:seriesEnded","title":"The meeting series has ended","status":409,"code":"seriesEnded"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/meeting-series/{seriesId}/overview":{"put":{"operationId":"meetings.saveOverview","summary":"Arrange the series overview","description":"Sets the modules of both columns, the hidden modules and the pinned items. The layout is the same for all members of the series.\n\nRequires the permission `item.edit` on the item in `seriesId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"seriesId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"seriesId","in":"path","required":true,"description":"ID of the meeting series.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"columns":{"minItems":2,"maxItems":2,"type":"array","items":{"maxItems":6,"type":"array","items":{"type":"string","maxLength":40}},"description":"Modules of the left and the right column. Known modules: topics, tasks, decisions, meetings, attendance, links."},"hidden":{"maxItems":6,"type":"array","items":{"type":"string","maxLength":40},"description":"Modules that are not shown. Modules left out anywhere are hidden too."},"links":{"maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"A page, folder, blog post or whiteboard of the same space."},"description":"Pinned items, up to 20."}},"required":["columns","hidden","links"],"additionalProperties":false,"description":"The overview layout."},"example":{"columns":[["topics","tasks"],["meetings","decisions"]],"hidden":["attendance","links"],"links":[]}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidLayout`: The overview layout is not valid. `invalidOverviewLink`: The overview cannot link this page. `tooManyOverviewLinks`: The overview links too many pages.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidLayout":{"value":{"type":"urn:lunedo:problem:invalidLayout","title":"The overview layout is not valid","status":400,"code":"invalidLayout"}},"invalidOverviewLink":{"value":{"type":"urn:lunedo:problem:invalidOverviewLink","title":"The overview cannot link this page","status":400,"code":"invalidOverviewLink"}},"tooManyOverviewLinks":{"value":{"type":"urn:lunedo:problem:tooManyOverviewLinks","title":"The overview links too many pages","status":400,"code":"tooManyOverviewLinks"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`seriesEnded`: The meeting series has ended.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"seriesEnded":{"value":{"type":"urn:lunedo:problem:seriesEnded","title":"The meeting series has ended","status":409,"code":"seriesEnded"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/meeting-series/{seriesId}/private-notes":{"get":{"operationId":"meetings.seriesNotes","summary":"List your private notes of a series","description":"Lists the caller's own private notes on the meetings of a series in one list.\n\nRequires the permission `item.view` on the item in `seriesId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"seriesId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"seriesId","in":"path","required":true,"description":"ID of the meeting series.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The notes.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"meetingId":{"type":"string","format":"uuid","description":"The meeting."},"meetingNumber":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the meeting in the addresses of the app."},"meetingTitle":{"type":"string","description":"Title of the meeting."},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start of the meeting. ISO 8601 timestamp in UTC."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"updatedAt":{"type":"string","format":"date-time","description":"When the notes were last saved. ISO 8601 timestamp in UTC."}},"required":["meetingId","meetingNumber","meetingTitle","startsAt","document","updatedAt"],"additionalProperties":false,"description":"Private notes on one meeting."},"description":"The caller's private notes in this series, newest meeting first."},"example":[{"meetingId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a10","meetingNumber":1051,"meetingTitle":"Jour fixe IT · 12 Oct 2026","startsAt":"2026-10-12T07:30:00.000Z","document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"updatedAt":"2026-10-12T07:40:00.000Z"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed. `notesNeedAccount`: Private notes belong to a person.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"notesNeedAccount":{"value":{"type":"urn:lunedo:problem:notesNeedAccount","title":"Private notes belong to a person","status":403,"code":"notesNeedAccount"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/meeting-series/{seriesId}/topic-order":{"put":{"operationId":"meetings.moveTopic","summary":"Move an open topic","description":"Places an open topic after another one. The order is the same in every meeting and for everyone.\n\nRequires the permission `item.edit` on the item in `seriesId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"seriesId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"seriesId","in":"path","required":true,"description":"ID of the meeting series.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"topicId":{"type":"string","format":"uuid","description":"The topic to move."},"afterId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The topic it goes after, or null for the top."}},"required":["topicId","afterId"],"additionalProperties":false,"description":"A new place of an open topic in the order of the series."},"example":{"topicId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6b00","afterId":null}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`seriesEnded`: The meeting series has ended.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"seriesEnded":{"value":{"type":"urn:lunedo:problem:seriesEnded","title":"The meeting series has ended","status":409,"code":"seriesEnded"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/meeting-series/{seriesId}/topics":{"get":{"operationId":"meetings.topics","summary":"List the running topics of a series","description":"Lists topics with filters for status, owner, label, period and title, the most recently updated first.\n\nRequires the permission `item.view` on the item in `seriesId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"seriesId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"seriesId","in":"path","required":true,"description":"ID of the meeting series.","schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","required":false,"description":"`open` (default), `closed` or `all`.","schema":{"default":"open","type":"string","enum":["open","closed","all"]}},{"name":"ownerId","in":"query","required":false,"description":"Only topics of this owner.","schema":{"type":"string","format":"uuid"}},{"name":"label","in":"query","required":false,"description":"Only topics with this label.","schema":{"type":"string","maxLength":100}},{"name":"from","in":"query","required":false,"description":"Only topics updated at or after this moment. ISO 8601 timestamp; an offset is allowed.","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"description":"Only topics updated before this moment. ISO 8601 timestamp; an offset is allowed.","schema":{"type":"string","format":"date-time"}},{"name":"text","in":"query","required":false,"description":"Only topics whose title contains this text.","schema":{"type":"string","maxLength":200}},{"name":"limit","in":"query","required":false,"description":"Maximum number of topics.","schema":{"default":200,"type":"integer","minimum":1,"maximum":500}}],"responses":{"200":{"description":"The topics.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the topic."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the topic in the addresses of the app."},"seriesId":{"type":"string","format":"uuid","description":"The series."},"seriesNumber":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the series in the addresses of the app."},"title":{"type":"string","description":"Title."},"status":{"type":"string","description":"Whether the topic is open. New values can be added in later versions; handle unknown values.","x-extensible-enum":["open","closed"]},"outcome":{"anyOf":[{"type":"string","x-extensible-enum":["resolved","decided","dropped"]},{"type":"null"}],"description":"How a closed topic ended. New values can be added in later versions; handle unknown values."},"owner":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, if visible.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who owns the topic."},"labels":{"type":"array","items":{"type":"string"},"description":"Labels."},"oneOff":{"type":"boolean","description":"True for a topic of one meeting only; it closes with that meeting."},"raisedIn":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Meeting ID."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the meeting in the addresses of the app."},"title":{"type":"string","description":"Title of the meeting."},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start of the meeting. ISO 8601 timestamp in UTC."}},"required":["id","number","title","startsAt"],"additionalProperties":false},{"type":"null"}],"description":"The meeting the topic was raised in, if the caller can read it."},"updates":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of updates the caller can read."},"openTasks":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Open tasks written in those updates."},"lastUpdateAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the last update was written. ISO 8601 timestamp in UTC."},"lastUpdateText":{"description":"Text of the last update that is not empty, in one line, or null when there is none.","type":["string","null"]},"createdAt":{"type":"string","format":"date-time","description":"When the topic was raised. ISO 8601 timestamp in UTC."},"closedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the topic was closed. ISO 8601 timestamp in UTC."},"decisionId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The decision that closed the topic."}},"required":["id","number","seriesId","seriesNumber","title","status","outcome","owner","labels","oneOff","raisedIn","updates","openTasks","lastUpdateAt","lastUpdateText","createdAt","closedAt","decisionId"],"additionalProperties":false,"description":"A running topic."},"description":"Topics."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6b00","number":1052,"seriesId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a00","seriesNumber":1050,"title":"Positions in AD","status":"open","outcome":null,"owner":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"labels":["directory"],"oneOff":false,"raisedIn":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a10","number":1051,"title":"Jour fixe IT · 12 Oct 2026","startsAt":"2026-10-12T07:30:00.000Z"},"updates":3,"openTasks":1,"lastUpdateAt":"2026-10-05T08:30:00.000Z","lastUpdateText":"Positions stay in AD; the sync runs nightly.","createdAt":"2026-09-21T08:00:00.000Z","closedAt":null,"decisionId":null}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"meetings.createTopic","summary":"Add a running topic","description":"Creates a topic and adds it to the upcoming meeting. Naming a meeting needs read access to it; a description, which goes into the notes of that meeting, and a topic for one meeting only need edit permission on it.\n\nRequires the permission `item.edit` on the item in `seriesId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"seriesId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"seriesId","in":"path","required":true,"description":"ID of the meeting series.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","maxLength":510,"description":"Title, 1 to 255 characters."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner; the caller when left out."},"labels":{"description":"Labels.","maxItems":20,"type":"array","items":{"type":"string","maxLength":200}},"meetingId":{"type":"string","format":"uuid","description":"Meeting the topic is raised in; the current meeting when left out."},"oneOff":{"description":"True for a topic of the given meeting only. It closes when that meeting is closed. Needs `meetingId`.","type":"boolean"},"description":{"description":"What the topic is about, up to 5000 characters. It becomes the topic's update in the meeting it is raised in, the first entry of its history. Needs a meeting that has not been closed.","type":"string","maxLength":5000}},"required":["title"],"additionalProperties":false,"description":"A new running topic. It is added to the upcoming meeting."},"example":{"title":"Positions in AD","labels":["directory"]}}}},"responses":{"201":{"description":"The topic.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the topic."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the topic in the addresses of the app."},"seriesId":{"type":"string","format":"uuid","description":"The series."},"seriesNumber":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the series in the addresses of the app."},"title":{"type":"string","description":"Title."},"status":{"type":"string","description":"Whether the topic is open. New values can be added in later versions; handle unknown values.","x-extensible-enum":["open","closed"]},"outcome":{"anyOf":[{"type":"string","x-extensible-enum":["resolved","decided","dropped"]},{"type":"null"}],"description":"How a closed topic ended. New values can be added in later versions; handle unknown values."},"owner":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, if visible.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who owns the topic."},"labels":{"type":"array","items":{"type":"string"},"description":"Labels."},"oneOff":{"type":"boolean","description":"True for a topic of one meeting only; it closes with that meeting."},"raisedIn":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Meeting ID."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the meeting in the addresses of the app."},"title":{"type":"string","description":"Title of the meeting."},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start of the meeting. ISO 8601 timestamp in UTC."}},"required":["id","number","title","startsAt"],"additionalProperties":false},{"type":"null"}],"description":"The meeting the topic was raised in, if the caller can read it."},"updates":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of updates the caller can read."},"openTasks":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Open tasks written in those updates."},"lastUpdateAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the last update was written. ISO 8601 timestamp in UTC."},"lastUpdateText":{"description":"Text of the last update that is not empty, in one line, or null when there is none.","type":["string","null"]},"createdAt":{"type":"string","format":"date-time","description":"When the topic was raised. ISO 8601 timestamp in UTC."},"closedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the topic was closed. ISO 8601 timestamp in UTC."},"decisionId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The decision that closed the topic."},"spaceId":{"type":"string","format":"uuid","description":"Space of the topic."},"seriesTitle":{"type":"string","description":"Name of the series."},"timeline":{"type":"array","items":{"type":"object","properties":{"meetingId":{"type":"string","format":"uuid","description":"Meeting the update was written in."},"meetingNumber":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of that meeting in the addresses of the app."},"meetingTitle":{"type":"string","description":"Title of that meeting."},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start of that meeting. ISO 8601 timestamp in UTC."},"content":{"type":"array","items":{"$ref":"#/components/schemas/Schema113ae44d8375"},"description":"The update as blocks of the editor schema."},"updatedAt":{"type":"string","format":"date-time","description":"When the update was last changed. ISO 8601 timestamp in UTC."}},"required":["meetingId","meetingNumber","meetingTitle","startsAt","content","updatedAt"],"additionalProperties":false,"description":"An update."},"description":"All updates the caller can read, oldest first. Skipped meetings are left out."},"decision":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Decision ID."},"itemId":{"type":"string","format":"uuid","description":"Page that holds the decision."},"itemNumber":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of that page in the addresses of the app."},"itemTitle":{"type":"string","description":"Title of that page."},"statement":{"type":"array","items":{"$ref":"#/components/schemas/Schemafbc378f59d82"},"description":"The statement as blocks of the editor schema."},"text":{"type":"string","description":"The statement as plain text."}},"required":["id","itemId","itemNumber","itemTitle","statement","text"],"additionalProperties":false},{"type":"null"}],"description":"The decision that closed the topic, if the caller can read it."}},"required":["id","number","seriesId","seriesNumber","title","status","outcome","owner","labels","oneOff","raisedIn","updates","openTasks","lastUpdateAt","lastUpdateText","createdAt","closedAt","decisionId","spaceId","seriesTitle","timeline","decision"],"additionalProperties":false,"description":"A running topic with its history."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6b00","number":1052,"seriesId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a00","seriesNumber":1050,"title":"Positions in AD","status":"open","outcome":null,"owner":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"labels":["directory"],"oneOff":false,"raisedIn":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a10","number":1051,"title":"Jour fixe IT · 12 Oct 2026","startsAt":"2026-10-12T07:30:00.000Z"},"updates":3,"openTasks":1,"lastUpdateAt":"2026-10-05T08:30:00.000Z","lastUpdateText":"Positions stay in AD; the sync runs nightly.","createdAt":"2026-09-21T08:00:00.000Z","closedAt":null,"decisionId":null,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a00","seriesTitle":"Jour fixe IT","timeline":[],"decision":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidLabel`: The label is not valid. `invalidMember`: The person cannot take part. `invalidTitle`: The title is not valid. `invalidUpdate`: The update is too long. `meetingRequired`: A topic for one meeting needs that meeting.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidLabel":{"value":{"type":"urn:lunedo:problem:invalidLabel","title":"The label is not valid","status":400,"code":"invalidLabel"}},"invalidMember":{"value":{"type":"urn:lunedo:problem:invalidMember","title":"The person cannot take part","status":400,"code":"invalidMember"}},"invalidTitle":{"value":{"type":"urn:lunedo:problem:invalidTitle","title":"The title is not valid","status":400,"code":"invalidTitle"}},"invalidUpdate":{"value":{"type":"urn:lunedo:problem:invalidUpdate","title":"The update is too long","status":400,"code":"invalidUpdate"}},"meetingRequired":{"value":{"type":"urn:lunedo:problem:meetingRequired","title":"A topic for one meeting needs that meeting","status":400,"code":"meetingRequired"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `meetingNotEditable`: The meeting notes cannot be edited.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"meetingNotEditable":{"value":{"type":"urn:lunedo:problem:meetingNotEditable","title":"The meeting notes cannot be edited","status":403,"code":"meetingNotEditable"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`seriesEnded`: The meeting series has ended. `tooManyLabels`: The page has too many labels.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"seriesEnded":{"value":{"type":"urn:lunedo:problem:seriesEnded","title":"The meeting series has ended","status":409,"code":"seriesEnded"}},"tooManyLabels":{"value":{"type":"urn:lunedo:problem:tooManyLabels","title":"The page has too many labels","status":409,"code":"tooManyLabels"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/meetings/{meetingId}":{"get":{"operationId":"meetings.meeting","summary":"Get a meeting","description":"Returns state, time and attendees of a meeting. The notes are the content of the meeting page; read them through the page content.\n\nRequires the permission `item.view` on the item in `meetingId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"meetingId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"meetingId","in":"path","required":true,"description":"ID of the meeting page.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The meeting.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the meeting page."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the meeting page in the addresses of the app."},"seriesId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The series, or null when the caller cannot read it."},"seriesNumber":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the series in the addresses of the app, or null when the caller cannot read it."},"seriesTitle":{"description":"Name of the series, or null when the caller cannot read it.","type":["string","null"]},"title":{"type":"string","description":"Title of the meeting page."},"state":{"type":"string","description":"`upcoming` is the next meeting, `closed` and `skipped` are done, `reopened` was closed and is open again. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upcoming","closed","reopened","skipped"]},"next":{"type":"boolean","description":"True for the next meeting of the series: the earliest one that is neither held nor skipped."},"current":{"type":"boolean","description":"Whether the meeting is open: upcoming or reopened."},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start, or null when not scheduled yet. ISO 8601 timestamp in UTC."},"recurrenceId":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Original start in the rhythm, or null. ISO 8601 timestamp in UTC."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Duration in minutes."},"timeZone":{"description":"Time zone of the series, or null when the caller cannot read the series.","type":["string","null"]},"closedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the meeting was closed or skipped. ISO 8601 timestamp in UTC."},"closedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, if visible.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who closed it."},"nextMeetingId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The meeting created when this one was closed or skipped, or null when the caller cannot read the series."},"previousMeeting":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the meeting."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the meeting in the addresses of the app."},"title":{"type":"string","description":"Title."},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start. ISO 8601 timestamp in UTC."}},"required":["id","number","title","startsAt"],"additionalProperties":false,"description":"A neighboring meeting."},{"type":"null"}],"description":"The meeting of the series before this one that the caller can read, skipped ones left out."},"followingMeeting":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the meeting."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the meeting in the addresses of the app."},"title":{"type":"string","description":"Title."},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start. ISO 8601 timestamp in UTC."}},"required":["id","number","title","startsAt"],"additionalProperties":false,"description":"A neighboring meeting."},{"type":"null"}],"description":"The meeting of the series after this one that the caller can read, skipped ones left out."},"rhythm":{"description":"Whether the series has a fixed rhythm; without one, closing asks for the next date. Null when the caller cannot read the series.","type":["boolean","null"]},"attendees":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, if visible.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null without one. Changes whenever the picture changes; load the picture from `GET /api/v1/accounts/{accountId}/picture`.","type":["string","null"]},"attendance":{"anyOf":[{"type":"string","x-extensible-enum":["present","excused","absent"]},{"type":"null"}],"description":"Attendance, or null when not recorded. New values can be added in later versions; handle unknown values."},"member":{"description":"Whether the person is a member of the series, or null when the caller cannot read it.","type":["boolean","null"]},"active":{"type":"boolean","description":"Whether the person can still take part: false when the account is deactivated, not set up yet or no longer a member of the organization. Always true for people the caller may not see."},"canRead":{"type":"boolean","description":"Whether the person can read the meeting page."}},"required":["id","name","pictureRef","attendance","member","active","canRead"],"additionalProperties":false,"description":"An attendee."},"description":"Attendees in order."},"extra":{"type":"boolean","description":"True for an additional meeting outside the rhythm."},"guests":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the guest entry."},"name":{"type":"string","description":"Name as entered."},"note":{"description":"Optional note, such as the company.","type":["string","null"]},"attendance":{"anyOf":[{"type":"string","x-extensible-enum":["present","excused","absent"]},{"type":"null"}],"description":"Attendance, or null when not recorded. New values can be added in later versions; handle unknown values."}},"required":["id","name","note","attendance"],"additionalProperties":false,"description":"A person without an account. Guests have no access to anything."},"description":"Guests without an account, in order."},"calendarUid":{"description":"Calendar UID of the meeting when it comes from a calendar.","type":["string","null"]}},"required":["id","number","seriesId","seriesNumber","seriesTitle","title","state","next","current","startsAt","recurrenceId","durationMinutes","timeZone","closedAt","closedBy","nextMeetingId","previousMeeting","followingMeeting","rhythm","attendees","extra","guests","calendarUid"],"additionalProperties":false,"description":"A meeting."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a10","number":1051,"seriesId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a00","seriesNumber":1050,"seriesTitle":"Jour fixe IT","title":"Jour fixe IT · 12 Oct 2026","state":"upcoming","next":true,"current":true,"startsAt":"2026-10-12T07:30:00.000Z","recurrenceId":"2026-10-12T07:30:00.000Z","durationMinutes":45,"timeZone":"Europe/Vienna","closedAt":null,"closedBy":null,"nextMeetingId":null,"previousMeeting":null,"followingMeeting":null,"rhythm":true,"attendees":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger","pictureRef":null,"attendance":"present","member":true,"active":true,"canRead":true}],"extra":false,"guests":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6c00","name":"Martin Huber","note":"Printer service","attendance":null}],"calendarUid":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/meetings/{meetingId}/agenda":{"get":{"operationId":"meetings.agenda","summary":"Get the agenda of a meeting","description":"Returns the topics of the meeting in the order of the series: all open topics while the meeting is open, the discussed topics once it is closed. Each topic has this meeting's update, its earlier updates and its tasks. Also returns the decisions and tasks written in this meeting.\n\nRequires the permission `item.view` on the item in `meetingId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"meetingId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"meetingId","in":"path","required":true,"description":"ID of the meeting page.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The agenda.","content":{"application/json":{"schema":{"type":"object","properties":{"meetingId":{"type":"string","format":"uuid","description":"The meeting."},"meetingNumber":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the meeting in the addresses of the app."},"seriesId":{"type":"string","format":"uuid","description":"Its series."},"seriesNumber":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of its series in the addresses of the app."},"current":{"type":"boolean","description":"True while the meeting is open: then the list holds all open topics. A closed meeting lists the topics it discussed."},"topics":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the topic."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the topic in the addresses of the app."},"title":{"type":"string","description":"Title."},"status":{"type":"string","description":"Whether the topic is open. New values can be added in later versions; handle unknown values.","x-extensible-enum":["open","closed"]},"outcome":{"anyOf":[{"type":"string","x-extensible-enum":["resolved","decided","dropped"]},{"type":"null"}],"description":"How a closed topic ended. New values can be added in later versions; handle unknown values."},"oneOff":{"type":"boolean","description":"True for a topic of this meeting only; it closes with the meeting."},"owner":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, if visible.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who owns the topic."},"labels":{"type":"array","items":{"type":"string"},"description":"Labels."},"createdAt":{"type":"string","format":"date-time","description":"When the topic was raised. ISO 8601 timestamp in UTC."},"update":{"anyOf":[{"type":"object","properties":{"text":{"type":"string","description":"The update of this meeting as plain text, paragraphs on own lines."},"formatted":{"type":"boolean","description":"True when the update has formatting; change it in the notes then."}},"required":["text","formatted"],"additionalProperties":false},{"type":"null"}],"description":"This meeting's update, or null when the notes have no block for the topic."},"previous":{"type":"array","items":{"type":"object","properties":{"meetingId":{"type":"string","format":"uuid","description":"Meeting of the update."},"meetingNumber":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of that meeting in the addresses of the app."},"meetingTitle":{"type":"string","description":"Title of that meeting."},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start of that meeting. ISO 8601 timestamp in UTC."},"text":{"type":"string","description":"The update as plain text."}},"required":["meetingId","meetingNumber","meetingTitle","startsAt","text"],"additionalProperties":false,"description":"An earlier update."},"description":"The last earlier updates the caller can read, newest first."},"history":{"type":"array","items":{"type":"object","properties":{"meetingId":{"type":"string","format":"uuid","description":"Meeting of the update."},"meetingNumber":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of that meeting in the addresses of the app."},"meetingTitle":{"type":"string","description":"Title of that meeting."},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start of that meeting. ISO 8601 timestamp in UTC."},"text":{"type":"string","description":"The update as plain text."}},"required":["meetingId","meetingNumber","meetingTitle","startsAt","text"],"additionalProperties":false,"description":"An earlier update."},"description":"All updates of meetings before this one that the caller can read, oldest first. The first is the start of the topic."},"meetings":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"How many meetings of the series the topic has been on, this one included."},"tasks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the task."},"text":{"type":"string","description":"Text of the task."},"done":{"type":"boolean","description":"Whether the task is done."},"dueDate":{"description":"Due date as `YYYY-MM-DD`, or null.","type":["string","null"]},"assignee":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, if visible.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"The assignee, or null."},"meetingId":{"type":"string","format":"uuid","description":"Meeting the task was written in."}},"required":["id","text","done","dueDate","assignee","meetingId"],"additionalProperties":false,"description":"A task."},"description":"Tasks written in the updates of this topic."}},"required":["id","number","title","status","outcome","oneOff","owner","labels","createdAt","update","previous","history","meetings","tasks"],"additionalProperties":false,"description":"A topic on the agenda."},"description":"Topics in the order of the series."},"closedTopics":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"How many topics were closed in this meeting."},"decisions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Decision ID."},"topicId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Topic it closed, or null."},"topicTitle":{"description":"Title of that topic, if visible.","type":["string","null"]},"text":{"type":"string","description":"The statement as plain text."}},"required":["id","topicId","topicTitle","text"],"additionalProperties":false,"description":"A decision."},"description":"Decisions recorded in this meeting."},"tasks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the task."},"text":{"type":"string","description":"Text of the task."},"done":{"type":"boolean","description":"Whether the task is done."},"dueDate":{"description":"Due date as `YYYY-MM-DD`, or null.","type":["string","null"]},"assignee":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, if visible.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"The assignee, or null."},"meetingId":{"type":"string","format":"uuid","description":"Meeting the task was written in."}},"required":["id","text","done","dueDate","assignee","meetingId"],"additionalProperties":false,"description":"A task."},"description":"Tasks written in this meeting."}},"required":["meetingId","meetingNumber","seriesId","seriesNumber","current","topics","closedTopics","decisions","tasks"],"additionalProperties":false,"description":"The agenda of a meeting."},"example":{"meetingId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a10","meetingNumber":1051,"seriesId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a00","seriesNumber":1050,"current":true,"topics":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6b00","number":1052,"title":"Positions in AD","status":"open","outcome":null,"oneOff":false,"owner":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"labels":["directory"],"createdAt":"2026-09-21T08:00:00.000Z","update":{"text":"HR sends the list on Friday.","formatted":false},"previous":[],"history":[],"meetings":1,"tasks":[]}],"closedTopics":0,"decisions":[],"tasks":[]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/meetings/{meetingId}/attendees":{"post":{"operationId":"meetings.addAttendee","summary":"Add an attendee","description":"Adds a person beyond the members of the series. Someone without read access is listed with `canRead: false`; share the meeting page with them to give access.\n\nRequires the permission `item.edit` on the item in `meetingId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"meetingId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"meetingId","in":"path","required":true,"description":"ID of the meeting page.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"The person to add."}},"required":["accountId"],"additionalProperties":false,"description":"An attendee beyond the members."},"example":{"accountId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a21"}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidMember`: The person cannot take part. `tooManyAttendees`: The meeting has too many attendees.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidMember":{"value":{"type":"urn:lunedo:problem:invalidMember","title":"The person cannot take part","status":400,"code":"invalidMember"}},"tooManyAttendees":{"value":{"type":"urn:lunedo:problem:tooManyAttendees","title":"The meeting has too many attendees","status":400,"code":"tooManyAttendees"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/meetings/{meetingId}/attendees/{accountId}":{"delete":{"operationId":"meetings.removeAttendee","summary":"Remove an attendee","description":"Removes a person from the attendees of this meeting. Series members stay members.\n\nRequires the permission `item.edit` on the item in `meetingId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"meetingId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"meetingId","in":"path","required":true,"description":"ID of the meeting page.","schema":{"type":"string","format":"uuid"}},{"name":"accountId","in":"path","required":true,"description":"ID of the attendee.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"put":{"operationId":"meetings.attendance","summary":"Record attendance","description":"Sets present, excused or absent for an attendee. Attendance is stored apart from the notes.\n\nRequires the permission `item.edit` on the item in `meetingId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"meetingId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"meetingId","in":"path","required":true,"description":"ID of the meeting page.","schema":{"type":"string","format":"uuid"}},{"name":"accountId","in":"path","required":true,"description":"ID of the attendee.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"attendance":{"anyOf":[{"type":"string","enum":["present","excused","absent"]},{"type":"null"}],"description":"`present`, `excused`, `absent`, or null to clear."}},"required":["attendance"],"additionalProperties":false,"description":"The attendance of one attendee."},"example":{"attendance":"present"}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`attendeeNotFound`: The person is not an attendee. `notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"attendeeNotFound":{"value":{"type":"urn:lunedo:problem:attendeeNotFound","title":"The person is not an attendee","status":404,"code":"attendeeNotFound"}},"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/meetings/{meetingId}/close":{"post":{"operationId":"meetings.close","summary":"Close a meeting","description":"Closes the meeting and notifies the attendees that the notes are available. Closing the upcoming meeting creates the next one: the next occurrence of the rhythm after now, or, without a fixed rhythm, at `nextStartsAt`. When two people close at the same moment, one succeeds and the other gets `meetingClosed`. A meeting can be closed from its day on, in the time zone of the series; before that the answer is `meetingInFuture`.\n\nRequires the permission `item.edit` on the item in `meetingId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"meetingId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"meetingId","in":"path","required":true,"description":"ID of the meeting page.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"nextStartsAt":{"description":"For a series without a fixed rhythm: the start of the next meeting, or null for `not scheduled yet`. Ignored with a rhythm.","anyOf":[{"description":"Start of the next meeting for a series without a fixed rhythm. ISO 8601 timestamp; an offset is allowed.","type":"string","format":"date-time"},{"type":"null"}]}},"additionalProperties":false,"description":"How to continue the series."},"example":{}}}},"responses":{"200":{"description":"The meeting created next, if any.","content":{"application/json":{"schema":{"type":"object","properties":{"nextMeetingId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The next meeting, or null after closing a reopened meeting."}},"required":["nextMeetingId"],"additionalProperties":false,"description":"The result."},"example":{"nextMeetingId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a11"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `nextDateRequired`: The date of the next meeting is required.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"nextDateRequired":{"value":{"type":"urn:lunedo:problem:nextDateRequired","title":"The date of the next meeting is required","status":400,"code":"nextDateRequired"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`meetingClosed`: The meeting is closed already. `meetingInFuture`: The meeting has not taken place yet. `seriesEnded`: The meeting series has ended.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"meetingClosed":{"value":{"type":"urn:lunedo:problem:meetingClosed","title":"The meeting is closed already","status":409,"code":"meetingClosed"}},"meetingInFuture":{"value":{"type":"urn:lunedo:problem:meetingInFuture","title":"The meeting has not taken place yet","status":409,"code":"meetingInFuture"}},"seriesEnded":{"value":{"type":"urn:lunedo:problem:seriesEnded","title":"The meeting series has ended","status":409,"code":"seriesEnded"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/meetings/{meetingId}/close/undo":{"post":{"operationId":"meetings.undoClose","summary":"Undo closing a meeting","description":"Opens a closed meeting again. The meeting created by closing it is removed while nobody has touched it; otherwise it stays and this works like reopening. Unread notifications about the notes are withdrawn.\n\nRequires the permission `item.edit` on the item in `meetingId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"meetingId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"meetingId","in":"path","required":true,"description":"ID of the meeting page.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The removed meeting, if any.","content":{"application/json":{"schema":{"type":"object","properties":{"removedMeetingId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The next meeting that was removed, or null."}},"required":["removedMeetingId"],"additionalProperties":false,"description":"The result."},"example":{"removedMeetingId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a11"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`meetingNotClosed`: The meeting is not closed. `seriesEnded`: The meeting series has ended.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"meetingNotClosed":{"value":{"type":"urn:lunedo:problem:meetingNotClosed","title":"The meeting is not closed","status":409,"code":"meetingNotClosed"}},"seriesEnded":{"value":{"type":"urn:lunedo:problem:seriesEnded","title":"The meeting series has ended","status":409,"code":"seriesEnded"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/meetings/{meetingId}/guests":{"post":{"operationId":"meetings.addGuest","summary":"Add a guest without an account","description":"Records a person without an account for the attendance of this meeting, for example a service provider. Guests get no access to anything.\n\nRequires the permission `item.edit` on the item in `meetingId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"meetingId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"meetingId","in":"path","required":true,"description":"ID of the meeting page.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":400,"description":"Name of the person, 1 to 200 characters."},"note":{"description":"Optional note, up to 500 characters.","anyOf":[{"type":"string","maxLength":1000},{"type":"null"}]}},"required":["name"],"additionalProperties":false,"description":"A guest without an account, recorded for the attendance of this meeting only."},"example":{"name":"Martin Huber","note":"Printer service"}}}},"responses":{"201":{"description":"The guest entry.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the guest entry."}},"required":["id"],"additionalProperties":false,"description":"The new guest entry."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6c00"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidGuestName`: The name of the guest is not valid. `invalidGuestNote`: The note about the guest is too long. `invalidInput`: The request is not valid. `tooManyGuests`: The meeting has too many guests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidGuestName":{"value":{"type":"urn:lunedo:problem:invalidGuestName","title":"The name of the guest is not valid","status":400,"code":"invalidGuestName"}},"invalidGuestNote":{"value":{"type":"urn:lunedo:problem:invalidGuestNote","title":"The note about the guest is too long","status":400,"code":"invalidGuestNote"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"tooManyGuests":{"value":{"type":"urn:lunedo:problem:tooManyGuests","title":"The meeting has too many guests","status":400,"code":"tooManyGuests"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/meetings/{meetingId}/guests/{guestId}":{"delete":{"operationId":"meetings.removeGuest","summary":"Remove a guest","description":"Removes a guest without an account from this meeting.\n\nRequires the permission `item.edit` on the item in `meetingId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"meetingId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"meetingId","in":"path","required":true,"description":"ID of the meeting page.","schema":{"type":"string","format":"uuid"}},{"name":"guestId","in":"path","required":true,"description":"ID of the guest entry.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`guestNotFound`: The guest is not on this meeting. `notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"guestNotFound":{"value":{"type":"urn:lunedo:problem:guestNotFound","title":"The guest is not on this meeting","status":404,"code":"guestNotFound"}},"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"put":{"operationId":"meetings.guestAttendance","summary":"Record the attendance of a guest","description":"Sets present, excused or absent for a guest without an account.\n\nRequires the permission `item.edit` on the item in `meetingId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"meetingId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"meetingId","in":"path","required":true,"description":"ID of the meeting page.","schema":{"type":"string","format":"uuid"}},{"name":"guestId","in":"path","required":true,"description":"ID of the guest entry.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"attendance":{"anyOf":[{"type":"string","enum":["present","excused","absent"]},{"type":"null"}],"description":"`present`, `excused`, `absent`, or null to clear."}},"required":["attendance"],"additionalProperties":false,"description":"The attendance of one attendee."},"example":{"attendance":"present"}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`guestNotFound`: The guest is not on this meeting. `notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"guestNotFound":{"value":{"type":"urn:lunedo:problem:guestNotFound","title":"The guest is not on this meeting","status":404,"code":"guestNotFound"}},"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/meetings/{meetingId}/private-notes":{"get":{"operationId":"meetings.privateNotes","summary":"Get your private notes on a meeting","description":"Returns the caller's own private notes. Nobody else can read them: not the other attendees, not space admins, not administrators.\n\nRequires the permission `item.view` on the item in `meetingId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"meetingId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"meetingId","in":"path","required":true,"description":"ID of the meeting page.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The notes.","content":{"application/json":{"schema":{"type":"object","properties":{"meetingId":{"type":"string","format":"uuid","description":"The meeting."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"schemaVersion":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Version of the editor schema."},"revision":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Revision of the stored notes; 0 when there are none yet."},"updatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the notes were last saved. ISO 8601 timestamp in UTC."}},"required":["meetingId","document","schemaVersion","revision","updatedAt"],"additionalProperties":false,"description":"The caller's private notes on a meeting. Nobody else can read them."},"example":{"meetingId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a10","document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"schemaVersion":4,"revision":3,"updatedAt":"2026-10-12T07:40:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed. `notesNeedAccount`: Private notes belong to a person.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"notesNeedAccount":{"value":{"type":"urn:lunedo:problem:notesNeedAccount","title":"Private notes belong to a person","status":403,"code":"notesNeedAccount"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"put":{"operationId":"meetings.savePrivateNotes","summary":"Save your private notes on a meeting","description":"Stores the caller's private notes, validated against the editor schema. The revision must match the stored notes, so a save from another window is not overwritten.\n\nRequires the permission `item.view` on the item in `meetingId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"meetingId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"meetingId","in":"path","required":true,"description":"ID of the meeting page.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"revision":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"The revision the notes are based on; 0 for the first save. A mismatch is refused with `notesChanged`."}},"required":["document","revision"],"additionalProperties":false,"description":"Private notes to store."},"example":{"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"revision":3}}}},"responses":{"200":{"description":"The saved notes.","content":{"application/json":{"schema":{"type":"object","properties":{"meetingId":{"type":"string","format":"uuid","description":"The meeting."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"schemaVersion":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Version of the editor schema."},"revision":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Revision of the stored notes; 0 when there are none yet."},"updatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the notes were last saved. ISO 8601 timestamp in UTC."}},"required":["meetingId","document","schemaVersion","revision","updatedAt"],"additionalProperties":false,"description":"The caller's private notes on a meeting. Nobody else can read them."},"example":{"meetingId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a10","document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"schemaVersion":4,"revision":3,"updatedAt":"2026-10-12T07:40:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidDocument`: The document does not match the editor schema. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidDocument":{"value":{"type":"urn:lunedo:problem:invalidDocument","title":"The document does not match the editor schema","status":400,"code":"invalidDocument"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `notesNeedAccount`: Private notes belong to a person.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"notesNeedAccount":{"value":{"type":"urn:lunedo:problem:notesNeedAccount","title":"Private notes belong to a person","status":403,"code":"notesNeedAccount"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notesChanged`: The private notes were changed elsewhere.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notesChanged":{"value":{"type":"urn:lunedo:problem:notesChanged","title":"The private notes were changed elsewhere","status":409,"code":"notesChanged"}}}}}},"413":{"description":"`notesTooLarge`: The private notes are too large.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notesTooLarge":{"value":{"type":"urn:lunedo:problem:notesTooLarge","title":"The private notes are too large","status":413,"code":"notesTooLarge"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/meetings/{meetingId}/reopen":{"post":{"operationId":"meetings.reopen","summary":"Reopen a closed meeting","description":"Opens a closed meeting again. The next meeting stays.\n\nRequires the permission `item.edit` on the item in `meetingId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"meetingId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"meetingId","in":"path","required":true,"description":"ID of the meeting page.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`meetingNotClosed`: The meeting is not closed. `seriesEnded`: The meeting series has ended.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"meetingNotClosed":{"value":{"type":"urn:lunedo:problem:meetingNotClosed","title":"The meeting is not closed","status":409,"code":"meetingNotClosed"}},"seriesEnded":{"value":{"type":"urn:lunedo:problem:seriesEnded","title":"The meeting series has ended","status":409,"code":"seriesEnded"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/meetings/{meetingId}/skip":{"post":{"operationId":"meetings.skip","summary":"Skip the upcoming meeting","description":"Marks the upcoming meeting as skipped and keeps its agenda. The following meeting is created with the agenda carried over.\n\nRequires the permission `item.edit` on the item in `meetingId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"meetingId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"meetingId","in":"path","required":true,"description":"ID of the meeting page.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"nextStartsAt":{"description":"For a series without a fixed rhythm: the start of the next meeting, or null for `not scheduled yet`. Ignored with a rhythm.","anyOf":[{"description":"Start of the next meeting for a series without a fixed rhythm. ISO 8601 timestamp; an offset is allowed.","type":"string","format":"date-time"},{"type":"null"}]}},"additionalProperties":false,"description":"How to continue the series."},"example":{}}}},"responses":{"200":{"description":"The following meeting.","content":{"application/json":{"schema":{"type":"object","properties":{"nextMeetingId":{"type":"string","format":"uuid","description":"The following meeting."}},"required":["nextMeetingId"],"additionalProperties":false,"description":"The result."},"example":{"nextMeetingId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a11"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `nextDateRequired`: The date of the next meeting is required.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"nextDateRequired":{"value":{"type":"urn:lunedo:problem:nextDateRequired","title":"The date of the next meeting is required","status":400,"code":"nextDateRequired"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`meetingNotUpcoming`: Only the upcoming meeting can change this way. `seriesEnded`: The meeting series has ended.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"meetingNotUpcoming":{"value":{"type":"urn:lunedo:problem:meetingNotUpcoming","title":"Only the upcoming meeting can change this way","status":409,"code":"meetingNotUpcoming"}},"seriesEnded":{"value":{"type":"urn:lunedo:problem:seriesEnded","title":"The meeting series has ended","status":409,"code":"seriesEnded"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/meetings/{meetingId}/start":{"put":{"operationId":"meetings.move","summary":"Move the upcoming meeting","description":"Sets a new start for the upcoming meeting. With a rhythm, the move is kept as a moved occurrence of the series.\n\nRequires the permission `item.edit` on the item in `meetingId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"meetingId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"meetingId","in":"path","required":true,"description":"ID of the meeting page.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"startsAt":{"anyOf":[{"description":"New start of the meeting. ISO 8601 timestamp; an offset is allowed.","type":"string","format":"date-time"},{"type":"null"}],"description":"New start, or null for `not scheduled yet` without a fixed rhythm."}},"required":["startsAt"],"additionalProperties":false,"description":"The new start."},"example":{"startsAt":"2026-10-13T12:00:00.000Z"}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `startRequired`: The start of the meeting is required.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"startRequired":{"value":{"type":"urn:lunedo:problem:startRequired","title":"The start of the meeting is required","status":400,"code":"startRequired"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`meetingNotUpcoming`: Only the upcoming meeting can change this way. `seriesEnded`: The meeting series has ended.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"meetingNotUpcoming":{"value":{"type":"urn:lunedo:problem:meetingNotUpcoming","title":"Only the upcoming meeting can change this way","status":409,"code":"meetingNotUpcoming"}},"seriesEnded":{"value":{"type":"urn:lunedo:problem:seriesEnded","title":"The meeting series has ended","status":409,"code":"seriesEnded"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/meetings/{meetingId}/topics/{topicId}/tasks":{"post":{"operationId":"meetings.addAgendaTask","summary":"Add a task to a topic","description":"Adds a task to the topic's block of the meeting notes. It appears in the tasks of the topic, the series and the assignee.\n\nRequires the permission `item.edit` on the item in `meetingId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"meetingId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"meetingId","in":"path","required":true,"description":"ID of the meeting page.","schema":{"type":"string","format":"uuid"}},{"name":"topicId","in":"path","required":true,"description":"ID of the running topic.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string","maxLength":1000,"description":"What is to be done, 1 to 500 characters."},"assigneeId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Who does it."},"dueDate":{"description":"Due date as `YYYY-MM-DD`.","anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]}},"required":["text"],"additionalProperties":false,"description":"A task for a topic, written into this meeting's update."},"example":{"text":"Send the list of positions","assigneeId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","dueDate":"2026-10-16"}}}},"responses":{"201":{"description":"The task.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the task."}},"required":["id"],"additionalProperties":false,"description":"The new task."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5c01"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidMember`: The person cannot take part. `invalidTask`: The task is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidMember":{"value":{"type":"urn:lunedo:problem:invalidMember","title":"The person cannot take part","status":400,"code":"invalidMember"}},"invalidTask":{"value":{"type":"urn:lunedo:problem:invalidTask","title":"The task is not valid","status":400,"code":"invalidTask"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`meetingClosed`: The meeting is closed already. `seriesEnded`: The meeting series has ended.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"meetingClosed":{"value":{"type":"urn:lunedo:problem:meetingClosed","title":"The meeting is closed already","status":409,"code":"meetingClosed"}},"seriesEnded":{"value":{"type":"urn:lunedo:problem:seriesEnded","title":"The meeting series has ended","status":409,"code":"seriesEnded"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/meetings/{meetingId}/topics/{topicId}/update":{"put":{"operationId":"meetings.saveUpdate","summary":"Save this meeting's update of a topic","description":"Writes the update into the topic's block of the meeting notes as plain paragraphs and keeps its tasks. An update with formatting is refused so that nothing gets lost; change it in the notes instead.\n\nRequires the permission `item.edit` on the item in `meetingId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"meetingId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"meetingId","in":"path","required":true,"description":"ID of the meeting page.","schema":{"type":"string","format":"uuid"}},{"name":"topicId","in":"path","required":true,"description":"ID of the running topic.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string","maxLength":5000,"description":"The update as plain text, up to 5000 characters. Empty clears it."}},"required":["text"],"additionalProperties":false,"description":"This meeting's update of a topic."},"example":{"text":"HR sends the list on Friday."}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidUpdate`: The update is too long.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidUpdate":{"value":{"type":"urn:lunedo:problem:invalidUpdate","title":"The update is too long","status":400,"code":"invalidUpdate"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`meetingClosed`: The meeting is closed already. `seriesEnded`: The meeting series has ended. `updateFormatted`: The update has formatting that plain text would lose.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"meetingClosed":{"value":{"type":"urn:lunedo:problem:meetingClosed","title":"The meeting is closed already","status":409,"code":"meetingClosed"}},"seriesEnded":{"value":{"type":"urn:lunedo:problem:seriesEnded","title":"The meeting series has ended","status":409,"code":"seriesEnded"}},"updateFormatted":{"value":{"type":"urn:lunedo:problem:updateFormatted","title":"The update has formatting that plain text would lose","status":409,"code":"updateFormatted"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/meetings/upcoming":{"get":{"operationId":"meetings.upcoming","summary":"List upcoming meetings","description":"Lists the next meeting of every series the caller can read, the soonest first.\n\nRequires the permission `instance.content.view` on the instance.","tags":["Meetings"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"oneOnOne","in":"query","required":false,"description":"`true` for one-on-ones only, `false` for other series only; both when left out.","schema":{"type":"string","enum":["true","false"]}},{"name":"limit","in":"query","required":false,"description":"Maximum number of meetings.","schema":{"default":10,"type":"integer","minimum":1,"maximum":50}}],"responses":{"200":{"description":"Upcoming meetings.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Meeting ID."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the meeting in the addresses of the app."},"title":{"type":"string","description":"Title."},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start, or null when not scheduled yet. ISO 8601 timestamp in UTC."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Duration in minutes."},"seriesId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The series, or null when the caller cannot read it."},"seriesNumber":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the series in the addresses of the app, or null when the caller cannot read it."},"seriesTitle":{"description":"Name of the series, or null when the caller cannot read it.","type":["string","null"]},"spaceId":{"type":"string","format":"uuid","description":"The space."},"spaceKey":{"type":"string","description":"Key of the space."},"oneOnOne":{"type":"boolean","description":"Whether it is a one-on-one."}},"required":["id","number","title","startsAt","durationMinutes","seriesId","seriesNumber","seriesTitle","spaceId","spaceKey","oneOnOne"],"additionalProperties":false,"description":"An upcoming meeting."},"description":"Upcoming meetings the caller can read, the soonest first."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a10","number":1051,"title":"Jour fixe IT · 12 Oct 2026","startsAt":"2026-10-12T07:30:00.000Z","durationMinutes":45,"seriesId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a00","seriesNumber":1050,"seriesTitle":"Jour fixe IT","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a00","spaceKey":"ITOPS","oneOnOne":false}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/mentions":{"get":{"operationId":"home.mentions","summary":"List mentions of the caller","description":"Lists the latest mentions of the caller in published content and comments the caller can read.\n\nRequires the permission `instance.content.view` on the instance.","tags":["Home"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"200":{"description":"Mentions, newest first.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the mention."},"item":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the page or blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app."},"kind":{"type":"string","description":"Kind of the item. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title readers see."},"spaceId":{"type":"string","format":"uuid","description":"Space of the item."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."},"mySpace":{"type":"boolean","description":"Whether the item lies in the caller's own personal space."}},"required":["id","number","kind","title","spaceId","spaceKey","spaceName","mySpace"],"additionalProperties":false,"description":"A page or blog post."},"commentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The comment with the mention, or null for a mention in the content."},"actor":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who mentioned the caller, or null."},"at":{"type":"string","format":"date-time","description":"When the mention became visible and notified the caller. ISO 8601 timestamp in UTC."}},"required":["id","item","commentId","actor","at"],"additionalProperties":false,"description":"A mention of the caller."},"description":"Mentions."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5e01","item":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"kind":"page","title":"VPN access for remote staff","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","mySpace":false},"commentId":null,"actor":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"at":"2026-10-07T08:00:00.000Z"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `personalOnly`: Only people have this personal data.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"personalOnly":{"value":{"type":"urn:lunedo:problem:personalOnly","title":"Only people have this personal data","status":400,"code":"personalOnly"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/one-on-ones":{"get":{"operationId":"oneOnOnes.list","summary":"List your one-on-ones","description":"Lists the one-on-ones of the caller with the other person and the next meeting.\n\nRequires the permission `instance.content.view` on the instance.","tags":["One-on-ones"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"200":{"description":"The one-on-ones.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"The confidential space."},"spaceKey":{"type":"string","description":"Its key."},"seriesId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The series."},"seriesNumber":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the series in the addresses of the app."},"partners":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null without one. Changes whenever the picture changes; load the picture from `GET /api/v1/accounts/{accountId}/picture`.","type":["string","null"]}},"required":["id","name","pictureRef"],"additionalProperties":false,"description":"A person."},"description":"The other people of the one-on-one."},"nextMeeting":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Meeting ID."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the meeting in the addresses of the app."},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start. ISO 8601 timestamp in UTC."}},"required":["id","number","startsAt"],"additionalProperties":false},{"type":"null"}],"description":"The next meeting."}},"required":["spaceId","spaceKey","seriesId","seriesNumber","partners","nextMeeting"],"additionalProperties":false,"description":"A one-on-one of the caller."},"description":"One-on-ones."},"example":[{"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5b00","spaceKey":"MSAB","seriesId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a00","seriesNumber":1050,"partners":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger","pictureRef":null}],"nextMeeting":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a10","number":1051,"startsAt":"2026-10-15T12:00:00.000Z"}}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"oneOnOnes.create","summary":"Start a one-on-one","description":"Creates a confidential space named after both people, with both as space admins, and a series from the one-on-one template. The other person is notified. Administrators cannot read it or give anyone access.\n\nRequires the permission `instance.content.view` on the instance.","tags":["One-on-ones"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"otherId":{"type":"string","format":"uuid","description":"The other person."},"organizationId":{"type":"string","format":"uuid","description":"Organization in which both are members; it owns the confidential space."},"rhythm":{"type":"object","properties":{"frequency":{"type":"string","enum":["none","daily","weekly","monthly","yearly"],"description":"`none` for no fixed rhythm, otherwise how often the meetings repeat."},"interval":{"default":1,"description":"Every how many days, weeks, months or years. 2 weekly is every two weeks, 3 monthly is quarterly.","type":"integer","minimum":1,"maximum":52},"weekdays":{"description":"For `weekly`: the weekdays of the meetings, at least one.","maxItems":7,"type":"array","items":{"type":"string","enum":["MO","TU","WE","TH","FR","SA","SU"],"description":"Weekday as in iCalendar: `MO` to `SU`."}},"monthDay":{"description":"For `monthly` by date: the day of the month.","type":"integer","minimum":1,"maximum":31},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"For `monthly` by weekday: the weekday, for example `TU`.","type":"string","enum":["MO","TU","WE","TH","FR","SA","SU"]}},"required":["frequency"],"additionalProperties":false,"description":"The rhythm of a series, as the interface offers it."},"startsOn":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Date of the first meeting in the series' time zone, YYYY-MM-DD."},"startTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$","description":"Local start time of the meetings, HH:MM in 24 hours."},"timeZone":{"type":"string","minLength":1,"maxLength":64,"description":"IANA time zone of the series, such as `Europe/Vienna`. Meetings keep their local time across daylight saving changes."},"durationMinutes":{"type":"integer","minimum":5,"maximum":1440,"description":"Duration of each meeting in minutes."}},"required":["otherId","organizationId","rhythm","startsOn","startTime","timeZone","durationMinutes"],"additionalProperties":false,"description":"A new one-on-one: a confidential space for two people with a series."},"example":{"otherId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f4a00","rhythm":{"frequency":"weekly","interval":2,"weekdays":["TH"]},"startsOn":"2026-10-15","startTime":"14:00","timeZone":"Europe/Vienna","durationMinutes":30}}}},"responses":{"201":{"description":"The one-on-one.","content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"The confidential space."},"seriesId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The series."},"seriesNumber":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the series in the addresses of the app."}},"required":["spaceId","seriesId","seriesNumber"],"additionalProperties":false,"description":"The one-on-one."},"example":{"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5b00","seriesId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a00","seriesNumber":1050}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidMember`: The person cannot take part. `invalidRhythm`: The rhythm is not valid. `invalidSchedule`: The schedule is not valid. `invalidTimeZone`: The time zone is not known.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidMember":{"value":{"type":"urn:lunedo:problem:invalidMember","title":"The person cannot take part","status":400,"code":"invalidMember"}},"invalidRhythm":{"value":{"type":"urn:lunedo:problem:invalidRhythm","title":"The rhythm is not valid","status":400,"code":"invalidRhythm"}},"invalidSchedule":{"value":{"type":"urn:lunedo:problem:invalidSchedule","title":"The schedule is not valid","status":400,"code":"invalidSchedule"}},"invalidTimeZone":{"value":{"type":"urn:lunedo:problem:invalidTimeZone","title":"The time zone is not known","status":400,"code":"invalidTimeZone"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"409":{"description":"`noSharedOrganization`: The two people share no organization.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"noSharedOrganization":{"value":{"type":"urn:lunedo:problem:noSharedOrganization","title":"The two people share no organization","status":409,"code":"noSharedOrganization"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/one-on-ones/organizations":{"get":{"operationId":"oneOnOnes.organizations","summary":"List organizations for a one-on-one","description":"Lists the organizations in which both the caller and the other person are members. A one-on-one is only possible in one of them; an empty list means it is not possible.\n\nRequires the permission `instance.content.view` on the instance.","tags":["One-on-ones"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"personId","in":"query","required":true,"description":"The other person.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The organizations.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Organization ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false,"description":"An organization."},"description":"Organizations in which both people are members."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f4a00","name":"Stadtwerke"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations":{"post":{"operationId":"organizations.create","summary":"Create an organization","description":"Creates an organization with an owner. The owner is the caller unless another account is named.\n\nRequires the permission `instance.organizations.create` on the instance.","tags":["Organizations"],"x-lunedo-permission":{"action":"instance.organizations.create","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Display name, 1 to 100 characters."},"slug":{"description":"Short name used in addresses. Derived from the name when left out.","type":"string","pattern":"^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$"},"language":{"description":"Default language. The instance default when left out.","type":"string","enum":["en","de"]},"timeZone":{"description":"Default IANA time zone. The instance default when left out.","type":"string"},"ownerAccountId":{"type":"string","format":"uuid","description":"Account that becomes owner. The caller when left out. Naming another account needs the permission `instance.organizations.manage`."}},"required":["name"],"additionalProperties":false,"description":"A new organization."},"example":{"name":"Example Inc.","language":"en","timeZone":"Europe/Vienna"}}}},"responses":{"201":{"description":"The new organization.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the organization."},"name":{"type":"string","description":"Display name, 1 to 100 characters."},"slug":{"type":"string","description":"Short name used in addresses: lowercase letters, digits and hyphens."},"logoRef":{"description":"Reference to the uploaded logo, or null.","type":["string","null"]},"language":{"type":"string","enum":["en","de"],"description":"Default language of the organization."},"timeZone":{"type":"string","description":"Default IANA time zone, for example `Europe/Vienna`."},"accentColor":{"type":"string","enum":["petrol","blue","violet","amber","red","green","gray"],"description":"Accent color from the palette, from the setting `branding.accentColor`."},"createdAt":{"type":"string","format":"date-time","description":"When the organization was created. ISO 8601 timestamp in UTC."}},"required":["id","name","slug","logoRef","language","timeZone","accentColor","createdAt"],"additionalProperties":false,"description":"An organization."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","name":"Example Inc.","slug":"example-inc","logoRef":null,"language":"en","timeZone":"Europe/Vienna","accentColor":"petrol","createdAt":"2026-10-01T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"409":{"description":"`slugTaken`: The slug is taken.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"slugTaken":{"value":{"type":"urn:lunedo:problem:slugTaken","title":"The slug is taken","status":409,"code":"slugTaken"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}":{"get":{"operationId":"organizations.get","summary":"Get an organization","description":"Returns an organization the caller is a member of.\n\nRequires the permission `organization.view` on the organization in `organizationId`.","tags":["Organizations"],"x-lunedo-permission":{"action":"organization.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The organization.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the organization."},"name":{"type":"string","description":"Display name, 1 to 100 characters."},"slug":{"type":"string","description":"Short name used in addresses: lowercase letters, digits and hyphens."},"logoRef":{"description":"Reference to the uploaded logo, or null.","type":["string","null"]},"language":{"type":"string","enum":["en","de"],"description":"Default language of the organization."},"timeZone":{"type":"string","description":"Default IANA time zone, for example `Europe/Vienna`."},"accentColor":{"type":"string","enum":["petrol","blue","violet","amber","red","green","gray"],"description":"Accent color from the palette, from the setting `branding.accentColor`."},"createdAt":{"type":"string","format":"date-time","description":"When the organization was created. ISO 8601 timestamp in UTC."}},"required":["id","name","slug","logoRef","language","timeZone","accentColor","createdAt"],"additionalProperties":false,"description":"An organization."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","name":"Example Inc.","slug":"example-inc","logoRef":null,"language":"en","timeZone":"Europe/Vienna","accentColor":"petrol","createdAt":"2026-10-01T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"patch":{"operationId":"organizations.update","summary":"Change an organization","description":"Changes name, slug, logo, language or time zone.\n\nRequires the permission `organization.update` on the organization in `organizationId`.","tags":["Organizations"],"x-lunedo-permission":{"action":"organization.update","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"New display name, 1 to 100 characters.","type":"string","minLength":1,"maxLength":100},"slug":{"description":"New short name used in addresses.","type":"string","pattern":"^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$"},"logoRef":{"description":"Reference to an uploaded logo, or null to remove it.","anyOf":[{"type":"string","minLength":1,"maxLength":500},{"type":"null"}]},"language":{"description":"New default language.","type":"string","enum":["en","de"]},"timeZone":{"description":"New default IANA time zone.","type":"string"}},"additionalProperties":false,"description":"Fields to change. Fields that are left out stay as they are."},"example":{"name":"Example Group"}}}},"responses":{"200":{"description":"The changed organization.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the organization."},"name":{"type":"string","description":"Display name, 1 to 100 characters."},"slug":{"type":"string","description":"Short name used in addresses: lowercase letters, digits and hyphens."},"logoRef":{"description":"Reference to the uploaded logo, or null.","type":["string","null"]},"language":{"type":"string","enum":["en","de"],"description":"Default language of the organization."},"timeZone":{"type":"string","description":"Default IANA time zone, for example `Europe/Vienna`."},"accentColor":{"type":"string","enum":["petrol","blue","violet","amber","red","green","gray"],"description":"Accent color from the palette, from the setting `branding.accentColor`."},"createdAt":{"type":"string","format":"date-time","description":"When the organization was created. ISO 8601 timestamp in UTC."}},"required":["id","name","slug","logoRef","language","timeZone","accentColor","createdAt"],"additionalProperties":false,"description":"An organization."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","name":"Example Inc.","slug":"example-inc","logoRef":null,"language":"en","timeZone":"Europe/Vienna","accentColor":"petrol","createdAt":"2026-10-01T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`slugTaken`: The slug is taken.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"slugTaken":{"value":{"type":"urn:lunedo:problem:slugTaken","title":"The slug is taken","status":409,"code":"slugTaken"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/access-overview":{"get":{"operationId":"accessRequests.overview","summary":"Export the permission overview as CSV","description":"Streams the access of every member, or of one person, as CSV for audits. Restricted pages the caller cannot read appear only as a number per space. The export is written to the audit log.\n\nRequires the permission `organization.access.view` on the organization in `organizationId`.","tags":["Access"],"x-lunedo-permission":{"action":"organization.access.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"accountId","in":"query","required":false,"description":"Only this person. Leave it out for every member.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The overview as CSV with a header row.","content":{"text/csv":{"schema":{"type":"string"},"example":"person,email,kind,space,page,role,pages,reason\r\n"}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/announcement":{"delete":{"operationId":"announcements.removeOrganization","summary":"Remove the organization announcement","description":"Removes the banner of the organization for all its members at once.\n\nRequires the permission `organization.settings.manage` on the organization in `organizationId`.","tags":["Announcements"],"x-lunedo-permission":{"action":"organization.settings.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"get":{"operationId":"announcements.organization","summary":"Get the organization announcement","description":"Returns the banner of the organization as set, also when it has ended or starts later.\n\nRequires the permission `organization.settings.view` on the organization in `organizationId`.","tags":["Announcements"],"x-lunedo-permission":{"action":"organization.settings.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The announcement.","content":{"application/json":{"schema":{"type":"object","properties":{"announcement":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the announcement. It stays the same when the announcement is changed."},"scope":{"type":"string","enum":["instance","organization"],"description":"Who set it."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The organization, or null for the instance."},"version":{"type":"string","format":"uuid","description":"Changes with every change of the announcement."},"severity":{"type":"string","enum":["information","warning"],"description":"`information` can be dismissed by each person until the announcement changes; `warning` stays until its end."},"text":{"type":"string","description":"The text."},"link":{"anyOf":[{"type":"object","properties":{"url":{"type":"string","maxLength":2000,"description":"Address starting with https:// or http://."},"label":{"type":"string","maxLength":60,"description":"Text of the link."}},"required":["url","label"],"additionalProperties":false,"description":"A link shown after the text."},{"type":"null"}],"description":"The link, or null."},"startsAt":{"type":"string","format":"date-time","description":"When it starts to show. ISO 8601 timestamp in UTC."},"endsAt":{"type":"string","format":"date-time","description":"When it stops showing. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When it was last changed. ISO 8601 timestamp in UTC."},"updatedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the person."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who changed it last."}},"required":["id","scope","organizationId","version","severity","text","link","startsAt","endsAt","updatedAt","updatedBy"],"additionalProperties":false,"description":"An announcement banner."},{"type":"null"}],"description":"The announcement, or null when none is set."}},"required":["announcement"],"additionalProperties":false,"description":"The current announcement."},"example":{"announcement":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","scope":"organization","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a01","version":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a41","severity":"information","text":"New: search in attachments. PDF, Word and Excel files are now searchable.","link":{"url":"https://wiki.example.org/spaces/ENG/blog","label":"Read the post"},"startsAt":"2026-10-14T08:00:00.000Z","endsAt":"2026-10-21T08:00:00.000Z","updatedAt":"2026-10-14T07:55:00.000Z","updatedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Weber"}}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"put":{"operationId":"announcements.setOrganization","summary":"Set the organization announcement","description":"Shows a banner on every screen of the organization's members, below the instance banner. Open sessions show the change at once.\n\nRequires the permission `organization.settings.manage` on the organization in `organizationId`.","tags":["Announcements"],"x-lunedo-permission":{"action":"organization.settings.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"severity":{"type":"string","enum":["information","warning"],"description":"`information` can be dismissed by each person until the announcement changes; `warning` stays until its end."},"text":{"type":"string","maxLength":300,"description":"Up to 300 characters."},"link":{"default":null,"description":"A link shown after the text, or null.","anyOf":[{"type":"object","properties":{"url":{"type":"string","maxLength":2000,"description":"Address starting with https:// or http://."},"label":{"type":"string","maxLength":60,"description":"Text of the link."}},"required":["url","label"],"additionalProperties":false},{"type":"null"}]},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When it starts to show, or null for now. ISO 8601 timestamp; an offset is allowed."},"endsAt":{"description":"When it stops showing. Needs to be in the future and after the start. ISO 8601 timestamp; an offset is allowed.","type":"string","format":"date-time"}},"required":["severity","text","endsAt"],"additionalProperties":false,"description":"The announcement. It replaces the current one; everyone sees it again, also people who dismissed it."},"example":{"severity":"information","text":"New: search in attachments. PDF, Word and Excel files are now searchable.","link":{"url":"https://wiki.example.org/spaces/ENG/blog","label":"Read the post"},"startsAt":null,"endsAt":"2026-10-21T08:00:00.000Z"}}}},"responses":{"200":{"description":"The announcement.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the announcement. It stays the same when the announcement is changed."},"scope":{"type":"string","enum":["instance","organization"],"description":"Who set it."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The organization, or null for the instance."},"version":{"type":"string","format":"uuid","description":"Changes with every change of the announcement."},"severity":{"type":"string","enum":["information","warning"],"description":"`information` can be dismissed by each person until the announcement changes; `warning` stays until its end."},"text":{"type":"string","description":"The text."},"link":{"anyOf":[{"type":"object","properties":{"url":{"type":"string","maxLength":2000,"description":"Address starting with https:// or http://."},"label":{"type":"string","maxLength":60,"description":"Text of the link."}},"required":["url","label"],"additionalProperties":false,"description":"A link shown after the text."},{"type":"null"}],"description":"The link, or null."},"startsAt":{"type":"string","format":"date-time","description":"When it starts to show. ISO 8601 timestamp in UTC."},"endsAt":{"type":"string","format":"date-time","description":"When it stops showing. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When it was last changed. ISO 8601 timestamp in UTC."},"updatedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the person."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who changed it last."}},"required":["id","scope","organizationId","version","severity","text","link","startsAt","endsAt","updatedAt","updatedBy"],"additionalProperties":false,"description":"An announcement banner."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","scope":"organization","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a01","version":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a41","severity":"information","text":"New: search in attachments. PDF, Word and Excel files are now searchable.","link":{"url":"https://wiki.example.org/spaces/ENG/blog","label":"Read the post"},"startsAt":"2026-10-14T08:00:00.000Z","endsAt":"2026-10-21T08:00:00.000Z","updatedAt":"2026-10-14T07:55:00.000Z","updatedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Weber"}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidAnnouncement`: The announcement is not valid. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidAnnouncement":{"value":{"type":"urn:lunedo:problem:invalidAnnouncement","title":"The announcement is not valid","status":400,"code":"invalidAnnouncement"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/audit-events":{"get":{"operationId":"audit.listOrganization","summary":"List audit events of an organization","description":"Lists events of the organization, newest first, with optional filters.\n\nRequires the permission `organization.audit.view` on the organization in `organizationId`.","tags":["Audit log"],"x-lunedo-permission":{"action":"organization.audit.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"from","in":"query","required":false,"description":"Only events at or after this time. ISO 8601 timestamp; an offset is allowed.","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"description":"Only events before this time. ISO 8601 timestamp; an offset is allowed.","schema":{"type":"string","format":"date-time"}},{"name":"actorId","in":"query","required":false,"description":"Only events of this account.","schema":{"type":"string","format":"uuid"}},{"name":"personId","in":"query","required":false,"description":"Only events about this person: those they did and those that name them as the target or the account or holder concerned.","schema":{"type":"string","format":"uuid"}},{"name":"targetType","in":"query","required":false,"description":"Only events about this kind of object, for example `group`.","schema":{"type":"string","maxLength":100}},{"name":"targetId","in":"query","required":false,"description":"Only events about this object. Combine it with `targetType`.","schema":{"type":"string","maxLength":200}},{"name":"name","in":"query","required":false,"description":"Only events of this type, for example `role.assigned`.","schema":{"type":"string","maxLength":100}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"A page of events.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the event."},"scopeType":{"type":"string","enum":["instance","organization"],"description":"Whether the event belongs to the instance or to an organization."},"scopeId":{"type":"string","format":"uuid","description":"ID of the organization, or the instance ID of all zeros."},"sequence":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Position in the tamper-evident chain of the scope."},"name":{"type":"string","description":"Event type, for example `role.assigned`."},"actorType":{"type":"string","description":"`account`, `system` or `anonymous`."},"actorId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Account that acted, or null."},"targetType":{"type":"string","description":"Kind of object the event is about."},"targetId":{"description":"ID of the object, or null.","type":["string","null"]},"fields":{"description":"Event details. Their shape depends on the event type.","$ref":"#/components/schemas/Schema113ae44d8375"},"occurredAt":{"type":"string","format":"date-time","description":"When the event happened. ISO 8601 timestamp in UTC."},"requestId":{"description":"ID of the HTTP request, or null.","type":["string","null"]},"clientIp":{"description":"Client IP address, or null.","type":["string","null"]},"userAgent":{"description":"User agent of the client, or null.","type":["string","null"]},"labelKey":{"type":"string","description":"Translation key of the action, `audit.events.` followed by the event type."},"changeKind":{"type":"string","enum":["setting","fields"],"description":"How `changes` reads: a setting value or lock, or changed fields."},"actor":{"type":"object","properties":{"type":{"type":"string","description":"`account`, `system` or `anonymous`."},"id":{"description":"ID of the account. For `system`, the part of Lunedo that acted: `setupAssistant` for the setup assistant before the owner account exists, or null for other automatic actions. More values may be added. Null for `anonymous`.","type":["string","null"]},"name":{"description":"Name of the account when the event happened, or null.","type":["string","null"]},"former":{"type":"boolean","description":"Whether the account was anonymized; its name and other personal data are gone."},"serviceAccount":{"type":"boolean","description":"Whether the account is a service account."},"token":{"description":"Name of the API token the account acted with, or null when it acted without one.","type":["string","null"]}},"required":["type","id","name","former","serviceAccount","token"],"additionalProperties":false,"description":"Who acted."},"target":{"type":"object","properties":{"type":{"type":"string","description":"Kind of object."},"id":{"description":"ID of the object, or for settings the setting key.","type":["string","null"]},"name":{"description":"Name of the object when the event happened, or null.","type":["string","null"]},"former":{"type":"boolean","description":"Whether the object is an anonymized account; its name and other personal data are gone."}},"required":["type","id","name","former"],"additionalProperties":false,"description":"What the event is about."},"scope":{"type":"object","properties":{"type":{"type":"string","enum":["instance","organization","account"],"description":"Instance, organization, or the account for events about one person's own account."},"id":{"description":"ID of the organization or account, null for the instance.","type":["string","null"]},"name":{"description":"Name of the organization or account when the event happened, or null.","type":["string","null"]}},"required":["type","id","name"],"additionalProperties":false,"description":"Where the event happened."},"changes":{"type":"array","items":{"type":"object","properties":{"property":{"type":"string","description":"Changed property or field."},"old":{"description":"Value before, or null when unknown or not set.","$ref":"#/components/schemas/Schemafbc378f59d82"},"new":{"description":"Value after, or null when removed.","$ref":"#/components/schemas/Schema682d67ac39ef"}},"required":["property","old","new"],"additionalProperties":false,"description":"One change."},"description":"What changed, readable without the raw fields."},"references":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"},"description":"Names of accounts, organizations, groups and roles that the fields refer to, by ID."},"formerAccounts":{"type":"array","items":{"type":"string"},"description":"Anonymized accounts the event refers to, shown as former users with their ID."},"peopleHidden":{"type":"boolean","description":"Whether the people involved are left out because the event concerns a confidential space the reader is not a member of. The actor, referenced accounts and their names are then empty."}},"required":["id","scopeType","scopeId","sequence","name","actorType","actorId","targetType","targetId","fields","occurredAt","requestId","clientIp","userAgent","labelKey","changeKind","actor","target","scope","changes","references","formerAccounts","peopleHidden"],"additionalProperties":false,"description":"An entry of the audit log."},"description":"Events, newest first."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"One page of results."},"example":{"items":[{"id":"01929b1f-5fc2-7fa6-97c3-bea0a18bd2e3","scopeType":"organization","scopeId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","sequence":42,"name":"role.assigned","actorType":"account","actorId":"01929b1e-8d4b-7e3f-a05c-4d3e2f1a6b7c","targetType":"roleAssignment","targetId":"01929b1e-9e5c-7f40-b16d-5e4f3a2b7c8d","fields":{"role":"Handbook editors","principalKind":"group","principalId":"01929b1f-0a6d-7a51-827e-6f5a4b3c8d9e"},"occurredAt":"2026-10-01T08:00:00.000Z","requestId":"6f1c2b0e-5d4a-4c3b-9a2f-1e0d9c8b7a6f","clientIp":"203.0.113.7","userAgent":"curl/8.9.1","labelKey":"audit.events.role.assigned","changeKind":"fields","actor":{"type":"account","id":"01929b1e-8d4b-7e3f-a05c-4d3e2f1a6b7c","name":"Olivia Owner","former":false,"serviceAccount":false,"token":null},"target":{"type":"roleAssignment","id":"01929b1e-9e5c-7f40-b16d-5e4f3a2b7c8d","name":null,"former":false},"scope":{"type":"organization","id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","name":"Platform Team"},"changes":[{"property":"role","old":null,"new":"Handbook editors"},{"property":"principalKind","old":null,"new":"group"},{"property":"principalId","old":null,"new":"01929b1f-0a6d-7a51-827e-6f5a4b3c8d9e"}],"references":{"01929b1f-0a6d-7a51-827e-6f5a4b3c8d9e":"Editors"},"formerAccounts":[],"peopleHidden":false}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/audit-events/export":{"get":{"operationId":"audit.exportOrganization","summary":"Export audit events of an organization as CSV","description":"Streams all events of the organization that match the filters as CSV, newest first. The export itself is recorded in the audit log.\n\nRequires the permission `organization.audit.view` on the organization in `organizationId`.","tags":["Audit log"],"x-lunedo-permission":{"action":"organization.audit.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"from","in":"query","required":false,"description":"Only events at or after this time. ISO 8601 timestamp; an offset is allowed.","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"description":"Only events before this time. ISO 8601 timestamp; an offset is allowed.","schema":{"type":"string","format":"date-time"}},{"name":"actorId","in":"query","required":false,"description":"Only events of this account.","schema":{"type":"string","format":"uuid"}},{"name":"personId","in":"query","required":false,"description":"Only events about this person: those they did and those that name them as the target or the account or holder concerned.","schema":{"type":"string","format":"uuid"}},{"name":"targetType","in":"query","required":false,"description":"Only events about this kind of object, for example `group`.","schema":{"type":"string","maxLength":100}},{"name":"targetId","in":"query","required":false,"description":"Only events about this object. Combine it with `targetType`.","schema":{"type":"string","maxLength":200}},{"name":"name","in":"query","required":false,"description":"Only events of this type, for example `role.assigned`.","schema":{"type":"string","maxLength":100}}],"responses":{"200":{"description":"The events as CSV with a header row.","content":{"text/csv":{"schema":{"type":"string"},"example":"time,actor,action,target,scope,changes,occurredAt,name,scopeType,scopeId,actorType,actorId,targetType,targetId,fields,clientIp,userAgent,requestId,sequence,id\r\n\"2026-10-01T08:00:00.000Z\",\"Olivia Owner\",\"role.assigned\",...\r\n"}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/blog":{"get":{"operationId":"blog.listOrganization","summary":"List the blog posts of an organization","description":"Lists published blog posts of all spaces of the organization the caller can read: pinned posts first, then the newest. Filter by space and label.\n\nRequires the permission `organization.view` on the organization in `organizationId`.","tags":["Blog"],"x-lunedo-permission":{"action":"organization.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Cursor from `nextCursor` of the previous page.","schema":{"type":"string","maxLength":500}},{"name":"limit","in":"query","required":false,"description":"Maximum number of posts, 1 to 100.","schema":{"default":30,"type":"integer","minimum":1,"maximum":100}},{"name":"spaceId","in":"query","required":false,"description":"Only posts of this space.","schema":{"type":"string","format":"uuid"}},{"name":"label","in":"query","required":false,"description":"Only posts with this label.","schema":{"type":"string","maxLength":100}}],"responses":{"200":{"description":"The posts.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the blog post in the addresses of the app."},"spaceId":{"type":"string","format":"uuid","description":"Space of the post."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."},"title":{"type":"string","description":"Title as readers see it."},"excerpt":{"type":"string","description":"Short summary shown in lists."},"labels":{"type":"array","items":{"type":"string","description":"A label."},"description":"Labels, sorted."},"author":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who wrote the post, or null."},"published":{"type":"boolean","description":"Whether the post was published. Unpublished posts are visible only to editors."},"publishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post was first published, or null. ISO 8601 timestamp in UTC."},"scheduledAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post will be published, or null. ISO 8601 timestamp in UTC."},"scheduledTimeZone":{"description":"Time zone the author scheduled it in, or null.","type":["string","null"]},"scheduledBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who scheduled the publication, or null."},"held":{"type":"boolean","description":"Whether the scheduled publication is waiting for a space admin because the person who scheduled it can no longer edit the post."},"pinnedInSpace":{"type":"boolean","description":"Whether the post is pinned at the top of its space's blog."},"pinnedInOrganization":{"type":"boolean","description":"Whether the post is pinned in the organization's blog overview."},"cover":{"anyOf":[{"type":"object","properties":{"attachmentId":{"type":"string","format":"uuid","description":"The image attachment."},"focusX":{"type":"number","description":"Horizontal focal point from 0 (left) to 1 (right)."},"focusY":{"type":"number","description":"Vertical focal point from 0 (top) to 1 (bottom)."}},"required":["attachmentId","focusX","focusY"],"additionalProperties":false},{"type":"null"}],"description":"Cover image with the point that stays visible in every crop, or null."},"commentCount":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Number of comments and replies on the post that are not deleted."},"createdAt":{"type":"string","format":"date-time","description":"When the post was created. ISO 8601 timestamp in UTC."}},"required":["id","number","spaceId","spaceKey","spaceName","title","excerpt","labels","author","published","publishedAt","scheduledAt","scheduledTimeZone","scheduledBy","held","pinnedInSpace","pinnedInOrganization","cover","commentCount","createdAt"],"additionalProperties":false,"description":"A blog post."},"description":"Posts: pinned ones first, then the newest."},"nextCursor":{"description":"Cursor for the next page, or null on the last page.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"Blog posts."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5d01","number":1077,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","title":"New VPN client from Monday","excerpt":"The company portal ships WireGuard 0.6 on Monday.","labels":["vpn"],"author":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"published":true,"publishedAt":"2026-10-06T07:00:00.000Z","scheduledAt":null,"scheduledTimeZone":null,"scheduledBy":null,"held":false,"pinnedInSpace":false,"pinnedInOrganization":true,"cover":{"attachmentId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","focusX":0.5,"focusY":0.3},"commentCount":4,"createdAt":"2026-10-05T15:00:00.000Z"}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/blog/pinned/{postId}":{"put":{"operationId":"blog.pinInOrganization","summary":"Pin a blog post in the organization overview","description":"Organization admins pin published posts at the top of the organization's blog overview.\n\nRequires the permission `organization.blog.pin` on the organization in `organizationId`.","tags":["Blog"],"x-lunedo-permission":{"action":"organization.blog.pin","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"postId","in":"path","required":true,"description":"ID of the blog post.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"pinned":{"type":"boolean","description":"True to pin, false to unpin."}},"required":["pinned"],"additionalProperties":false,"description":"Pinned state."},"example":{"pinned":true}}}},"responses":{"200":{"description":"The post.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the blog post in the addresses of the app."},"spaceId":{"type":"string","format":"uuid","description":"Space of the post."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."},"title":{"type":"string","description":"Title as readers see it."},"excerpt":{"type":"string","description":"Short summary shown in lists."},"labels":{"type":"array","items":{"type":"string","description":"A label."},"description":"Labels, sorted."},"author":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who wrote the post, or null."},"published":{"type":"boolean","description":"Whether the post was published. Unpublished posts are visible only to editors."},"publishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post was first published, or null. ISO 8601 timestamp in UTC."},"scheduledAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post will be published, or null. ISO 8601 timestamp in UTC."},"scheduledTimeZone":{"description":"Time zone the author scheduled it in, or null.","type":["string","null"]},"scheduledBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who scheduled the publication, or null."},"held":{"type":"boolean","description":"Whether the scheduled publication is waiting for a space admin because the person who scheduled it can no longer edit the post."},"pinnedInSpace":{"type":"boolean","description":"Whether the post is pinned at the top of its space's blog."},"pinnedInOrganization":{"type":"boolean","description":"Whether the post is pinned in the organization's blog overview."},"cover":{"anyOf":[{"type":"object","properties":{"attachmentId":{"type":"string","format":"uuid","description":"The image attachment."},"focusX":{"type":"number","description":"Horizontal focal point from 0 (left) to 1 (right)."},"focusY":{"type":"number","description":"Vertical focal point from 0 (top) to 1 (bottom)."}},"required":["attachmentId","focusX","focusY"],"additionalProperties":false},{"type":"null"}],"description":"Cover image with the point that stays visible in every crop, or null."},"commentCount":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Number of comments and replies on the post that are not deleted."},"createdAt":{"type":"string","format":"date-time","description":"When the post was created. ISO 8601 timestamp in UTC."}},"required":["id","number","spaceId","spaceKey","spaceName","title","excerpt","labels","author","published","publishedAt","scheduledAt","scheduledTimeZone","scheduledBy","held","pinnedInSpace","pinnedInOrganization","cover","commentCount","createdAt"],"additionalProperties":false,"description":"A blog post."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5d01","number":1077,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","title":"New VPN client from Monday","excerpt":"The company portal ships WireGuard 0.6 on Monday.","labels":["vpn"],"author":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"published":true,"publishedAt":"2026-10-06T07:00:00.000Z","scheduledAt":null,"scheduledTimeZone":null,"scheduledBy":null,"held":false,"pinnedInSpace":false,"pinnedInOrganization":true,"cover":{"attachmentId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","focusX":0.5,"focusY":0.3},"commentCount":4,"createdAt":"2026-10-05T15:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `notInOrganization`: The blog post does not belong to an organization.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"notInOrganization":{"value":{"type":"urn:lunedo:problem:notInOrganization","title":"The blog post does not belong to an organization","status":400,"code":"notInOrganization"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notPublished`: The blog post is not published.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notPublished":{"value":{"type":"urn:lunedo:problem:notPublished","title":"The blog post is not published","status":409,"code":"notPublished"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/chat-channels":{"get":{"operationId":"chatChannels.listOrganization","summary":"List the announcement channels of an organization","description":"Shows the channels with their state. Addresses and tokens are never returned.\n\nRequires the permission `organization.integrations.view` on the organization in `organizationId`.","tags":["Chat channels"],"x-lunedo-permission":{"action":"organization.integrations.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The channels.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the channel."},"kind":{"type":"string","description":"Service of the channel: Microsoft Teams (Workflows webhook), Slack, Matrix, Discord or a generic webhook. New values can be added in later versions; handle unknown values.","x-extensible-enum":["teams","slack","matrix","discord","webhook"]},"name":{"type":"string","description":"Name of the channel in Lunedo."},"events":{"type":"array","items":{"type":"string","description":"An event that is posted. New values can be added in later versions; handle unknown values.","x-extensible-enum":["pagePublished","pageChanged","blogPostPublished","decisionRecorded","pageStatusChanged","commentCreated","announcementPublished"]},"description":"What is posted."},"state":{"type":"string","description":"`failing` when the service stopped accepting messages; nothing is posted until the channel is fixed. New values can be added in later versions; handle unknown values.","x-extensible-enum":["working","failing"]},"failure":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Why the service did not accept messages. New values can be added in later versions; handle unknown values.","x-extensible-enum":["addressGone","unauthorized","rejected","unavailable","unreachable","blockedAddress","insecureAddress"]},"status":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"HTTP status the service answered with, if it answered."},"code":{"description":"Error code the service reported, such as `invalid_token`, if any.","type":["string","null"]},"at":{"type":"string","format":"date-time","description":"When the channel started failing or the last test failed. ISO 8601 timestamp in UTC."}},"required":["reason","status","code","at"],"additionalProperties":false},{"type":"null"}],"description":"Why the channel is failing, or, while it is `working`, why the last test failed. Null once a message was accepted again."},"lastAttemptAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When a message was last sent. ISO 8601 timestamp in UTC."},"lastDeliveredAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When a message was last accepted. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the channel was connected. ISO 8601 timestamp in UTC."}},"required":["id","kind","name","events","state","failure","lastAttemptAt","lastDeliveredAt","createdAt"],"additionalProperties":false,"description":"A chat channel. Addresses and tokens are never returned."},"description":"The channels."}},"required":["items"],"additionalProperties":false,"description":"Chat channels."},"example":{"items":[{"id":"0192a0d4-5b6e-7c3f-8a10-3e2f4c5d6e7f","kind":"teams","name":"IT-Ops · General","events":["pagePublished","blogPostPublished","decisionRecorded"],"state":"working","failure":null,"lastAttemptAt":"2026-10-15T08:12:00.000Z","lastDeliveredAt":"2026-10-15T08:12:00.000Z","createdAt":"2026-10-01T09:00:00.000Z"}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"chatChannels.createOrganization","summary":"Post organization announcements to a chat channel","description":"Announcements are posted when they start.\n\nRequires the permission `organization.integrations.manage` on the organization in `organizationId`.","tags":["Chat channels"],"x-lunedo-permission":{"action":"organization.integrations.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","description":"Service of the channel: Microsoft Teams (Workflows webhook), Slack, Matrix, Discord or a generic webhook. New values can be added in later versions; handle unknown values.","x-extensible-enum":["teams","slack","matrix","discord","webhook"]},"name":{"type":"string","minLength":1,"maxLength":80,"description":"Name of the channel in Lunedo."},"events":{"minItems":1,"maxItems":7,"type":"array","items":{"type":"string","enum":["pagePublished","pageChanged","blogPostPublished","decisionRecorded","pageStatusChanged","commentCreated","announcementPublished"]},"description":"What is posted. Spaces: `pagePublished`, `pageChanged` (combined per hour), `blogPostPublished`, `decisionRecorded`, `pageStatusChanged`, `commentCreated`. Organizations: `announcementPublished`."},"target":{"anyOf":[{"type":"object","properties":{"url":{"type":"string","minLength":1,"maxLength":2000,"description":"Webhook address the service created. Stored encrypted and never returned."}},"required":["url"],"additionalProperties":false,"description":"For Teams, Slack, Discord and generic webhooks."},{"type":"object","properties":{"homeserver":{"type":"string","minLength":1,"maxLength":2000,"description":"Address of the Matrix homeserver."},"roomId":{"type":"string","minLength":1,"maxLength":500,"description":"Room as people see it in their client: an alias such as `#ops:example.org`, a matrix.to link or a room ID such as `!abc:example.org`. Aliases and links are resolved to the room ID when saving."},"accessToken":{"type":"string","minLength":1,"maxLength":2000,"description":"Access token of the bot account. Stored encrypted and never returned."}},"required":["homeserver","roomId","accessToken"],"additionalProperties":false,"description":"For Matrix."}],"description":"Where messages go. Private, loopback and link-local addresses are refused unless the instance allows them."}},"required":["kind","name","events","target"],"additionalProperties":false,"description":"The channel to connect."},"example":{"kind":"teams","name":"IT-Ops · General","events":["announcementPublished"],"target":{"url":"https://prod-12.westeurope.logic.azure.com/workflows/abc/triggers/manual/paths/invoke"}}}}},"responses":{"201":{"description":"The channel.","content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the channel."},"kind":{"type":"string","description":"Service of the channel: Microsoft Teams (Workflows webhook), Slack, Matrix, Discord or a generic webhook. New values can be added in later versions; handle unknown values.","x-extensible-enum":["teams","slack","matrix","discord","webhook"]},"name":{"type":"string","description":"Name of the channel in Lunedo."},"events":{"type":"array","items":{"type":"string","description":"An event that is posted. New values can be added in later versions; handle unknown values.","x-extensible-enum":["pagePublished","pageChanged","blogPostPublished","decisionRecorded","pageStatusChanged","commentCreated","announcementPublished"]},"description":"What is posted."},"state":{"type":"string","description":"`failing` when the service stopped accepting messages; nothing is posted until the channel is fixed. New values can be added in later versions; handle unknown values.","x-extensible-enum":["working","failing"]},"failure":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Why the service did not accept messages. New values can be added in later versions; handle unknown values.","x-extensible-enum":["addressGone","unauthorized","rejected","unavailable","unreachable","blockedAddress","insecureAddress"]},"status":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"HTTP status the service answered with, if it answered."},"code":{"description":"Error code the service reported, such as `invalid_token`, if any.","type":["string","null"]},"at":{"type":"string","format":"date-time","description":"When the channel started failing or the last test failed. ISO 8601 timestamp in UTC."}},"required":["reason","status","code","at"],"additionalProperties":false},{"type":"null"}],"description":"Why the channel is failing, or, while it is `working`, why the last test failed. Null once a message was accepted again."},"lastAttemptAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When a message was last sent. ISO 8601 timestamp in UTC."},"lastDeliveredAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When a message was last accepted. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the channel was connected. ISO 8601 timestamp in UTC."}},"required":["id","kind","name","events","state","failure","lastAttemptAt","lastDeliveredAt","createdAt"],"additionalProperties":false,"description":"A chat channel. Addresses and tokens are never returned."},"signingSecret":{"description":"For generic webhooks, the secret that signs each request (header `X-Lunedo-Signature`). Shown only in this answer.","type":["string","null"]}},"required":["channel","signingSecret"],"additionalProperties":false,"description":"The saved channel."},"example":{"channel":{"id":"0192a0d4-5b6e-7c3f-8a10-3e2f4c5d6e7f","kind":"teams","name":"IT-Ops · General","events":["pagePublished","blogPostPublished","decisionRecorded"],"state":"working","failure":null,"lastAttemptAt":"2026-10-15T08:12:00.000Z","lastDeliveredAt":"2026-10-15T08:12:00.000Z","createdAt":"2026-10-01T09:00:00.000Z"},"signingSecret":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `chatAddressBlocked`: The address points to a private network. `chatAddressInsecure`: The address needs HTTPS. `invalidChatAddress`: The address of the chat service is not valid. `invalidChatChannel`: The chat channel is not valid. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"chatAddressBlocked":{"value":{"type":"urn:lunedo:problem:chatAddressBlocked","title":"The address points to a private network","status":400,"code":"chatAddressBlocked"}},"chatAddressInsecure":{"value":{"type":"urn:lunedo:problem:chatAddressInsecure","title":"The address needs HTTPS","status":400,"code":"chatAddressInsecure"}},"invalidChatAddress":{"value":{"type":"urn:lunedo:problem:invalidChatAddress","title":"The address of the chat service is not valid","status":400,"code":"invalidChatAddress"}},"invalidChatChannel":{"value":{"type":"urn:lunedo:problem:invalidChatChannel","title":"The chat channel is not valid","status":400,"code":"invalidChatChannel"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`confidentialSpace`: Confidential spaces cannot post to chat channels. `tooManyChatChannels`: There are too many chat channels.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"confidentialSpace":{"value":{"type":"urn:lunedo:problem:confidentialSpace","title":"Confidential spaces cannot post to chat channels","status":409,"code":"confidentialSpace"}},"tooManyChatChannels":{"value":{"type":"urn:lunedo:problem:tooManyChatChannels","title":"There are too many chat channels","status":409,"code":"tooManyChatChannels"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/chat-channels/{channelId}":{"delete":{"operationId":"chatChannels.removeOrganization","summary":"Disconnect an announcement channel","description":"Deletes the stored address; messages not yet sent are dropped.\n\nRequires the permission `organization.integrations.manage` on the organization in `organizationId`.","tags":["Chat channels"],"x-lunedo-permission":{"action":"organization.integrations.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"channelId","in":"path","required":true,"description":"ID of the chat channel.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"patch":{"operationId":"chatChannels.updateOrganization","summary":"Change an announcement channel","description":"A new address or secret also clears the failing state.\n\nRequires the permission `organization.integrations.manage` on the organization in `organizationId`.","tags":["Chat channels"],"x-lunedo-permission":{"action":"organization.integrations.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"channelId","in":"path","required":true,"description":"ID of the chat channel.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80,"description":"Name of the channel in Lunedo."},"events":{"minItems":1,"maxItems":7,"type":"array","items":{"type":"string","enum":["pagePublished","pageChanged","blogPostPublished","decisionRecorded","pageStatusChanged","commentCreated","announcementPublished"]},"description":"What is posted. Spaces: `pagePublished`, `pageChanged` (combined per hour), `blogPostPublished`, `decisionRecorded`, `pageStatusChanged`, `commentCreated`. Organizations: `announcementPublished`."},"target":{"description":"New address or token. Leave it out to keep the stored one.","anyOf":[{"type":"object","properties":{"url":{"type":"string","minLength":1,"maxLength":2000,"description":"Webhook address the service created. Stored encrypted and never returned."}},"required":["url"],"additionalProperties":false,"description":"For Teams, Slack, Discord and generic webhooks."},{"type":"object","properties":{"homeserver":{"type":"string","minLength":1,"maxLength":2000,"description":"Address of the Matrix homeserver."},"roomId":{"type":"string","minLength":1,"maxLength":500,"description":"Room as people see it in their client: an alias such as `#ops:example.org`, a matrix.to link or a room ID such as `!abc:example.org`. Aliases and links are resolved to the room ID when saving."},"accessToken":{"type":"string","minLength":1,"maxLength":2000,"description":"Access token of the bot account. Stored encrypted and never returned."}},"required":["homeserver","roomId","accessToken"],"additionalProperties":false,"description":"For Matrix."}]},"newSecret":{"description":"For generic webhooks: create a new signing secret, returned once in the answer.","type":"boolean"}},"additionalProperties":false,"description":"Changes to the channel."},"example":{"name":"All hands"}}}},"responses":{"200":{"description":"The channel.","content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the channel."},"kind":{"type":"string","description":"Service of the channel: Microsoft Teams (Workflows webhook), Slack, Matrix, Discord or a generic webhook. New values can be added in later versions; handle unknown values.","x-extensible-enum":["teams","slack","matrix","discord","webhook"]},"name":{"type":"string","description":"Name of the channel in Lunedo."},"events":{"type":"array","items":{"type":"string","description":"An event that is posted. New values can be added in later versions; handle unknown values.","x-extensible-enum":["pagePublished","pageChanged","blogPostPublished","decisionRecorded","pageStatusChanged","commentCreated","announcementPublished"]},"description":"What is posted."},"state":{"type":"string","description":"`failing` when the service stopped accepting messages; nothing is posted until the channel is fixed. New values can be added in later versions; handle unknown values.","x-extensible-enum":["working","failing"]},"failure":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Why the service did not accept messages. New values can be added in later versions; handle unknown values.","x-extensible-enum":["addressGone","unauthorized","rejected","unavailable","unreachable","blockedAddress","insecureAddress"]},"status":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"HTTP status the service answered with, if it answered."},"code":{"description":"Error code the service reported, such as `invalid_token`, if any.","type":["string","null"]},"at":{"type":"string","format":"date-time","description":"When the channel started failing or the last test failed. ISO 8601 timestamp in UTC."}},"required":["reason","status","code","at"],"additionalProperties":false},{"type":"null"}],"description":"Why the channel is failing, or, while it is `working`, why the last test failed. Null once a message was accepted again."},"lastAttemptAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When a message was last sent. ISO 8601 timestamp in UTC."},"lastDeliveredAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When a message was last accepted. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the channel was connected. ISO 8601 timestamp in UTC."}},"required":["id","kind","name","events","state","failure","lastAttemptAt","lastDeliveredAt","createdAt"],"additionalProperties":false,"description":"A chat channel. Addresses and tokens are never returned."},"signingSecret":{"description":"For generic webhooks, the secret that signs each request (header `X-Lunedo-Signature`). Shown only in this answer.","type":["string","null"]}},"required":["channel","signingSecret"],"additionalProperties":false,"description":"The saved channel."},"example":{"channel":{"id":"0192a0d4-5b6e-7c3f-8a10-3e2f4c5d6e7f","kind":"teams","name":"IT-Ops · General","events":["pagePublished","blogPostPublished","decisionRecorded"],"state":"working","failure":null,"lastAttemptAt":"2026-10-15T08:12:00.000Z","lastDeliveredAt":"2026-10-15T08:12:00.000Z","createdAt":"2026-10-01T09:00:00.000Z"},"signingSecret":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `chatAddressBlocked`: The address points to a private network. `chatAddressInsecure`: The address needs HTTPS. `invalidChatAddress`: The address of the chat service is not valid. `invalidChatChannel`: The chat channel is not valid. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"chatAddressBlocked":{"value":{"type":"urn:lunedo:problem:chatAddressBlocked","title":"The address points to a private network","status":400,"code":"chatAddressBlocked"}},"chatAddressInsecure":{"value":{"type":"urn:lunedo:problem:chatAddressInsecure","title":"The address needs HTTPS","status":400,"code":"chatAddressInsecure"}},"invalidChatAddress":{"value":{"type":"urn:lunedo:problem:invalidChatAddress","title":"The address of the chat service is not valid","status":400,"code":"invalidChatAddress"}},"invalidChatChannel":{"value":{"type":"urn:lunedo:problem:invalidChatChannel","title":"The chat channel is not valid","status":400,"code":"invalidChatChannel"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`confidentialSpace`: Confidential spaces cannot post to chat channels. `tooManyChatChannels`: There are too many chat channels.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"confidentialSpace":{"value":{"type":"urn:lunedo:problem:confidentialSpace","title":"Confidential spaces cannot post to chat channels","status":409,"code":"confidentialSpace"}},"tooManyChatChannels":{"value":{"type":"urn:lunedo:problem:tooManyChatChannels","title":"There are too many chat channels","status":409,"code":"tooManyChatChannels"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/chat-channels/{channelId}/test":{"post":{"operationId":"chatChannels.testSavedOrganization","summary":"Send a test message to an announcement channel","description":"When the service accepts it, a failing channel works again.\n\nRequires the permission `organization.integrations.manage` on the organization in `organizationId`.","tags":["Chat channels"],"x-lunedo-permission":{"action":"organization.integrations.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"channelId","in":"path","required":true,"description":"ID of the chat channel.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Whether the service accepted it.","content":{"application/json":{"schema":{"type":"object","properties":{"delivered":{"type":"boolean","description":"Whether the service accepted the test message."},"failure":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Why the service did not accept messages. New values can be added in later versions; handle unknown values.","x-extensible-enum":["addressGone","unauthorized","rejected","unavailable","unreachable","blockedAddress","insecureAddress"]},"status":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"HTTP status the service answered with, if it answered."},"code":{"description":"Error code the service reported, such as `invalid_token`, if any.","type":["string","null"]}},"required":["reason","status","code"],"additionalProperties":false,"description":"Why a message was not delivered."},{"type":"null"}],"description":"Why it was not accepted, or null."}},"required":["delivered","failure"],"additionalProperties":false,"description":"Result of the test message."},"example":{"delivered":false,"failure":{"reason":"addressGone","status":404,"code":"no_service"}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/chat-channels/test":{"post":{"operationId":"chatChannels.testOrganization","summary":"Send a test message before connecting an announcement channel","description":"Sends one message to the address without saving it.\n\nRequires the permission `organization.integrations.manage` on the organization in `organizationId`.","tags":["Chat channels"],"x-lunedo-permission":{"action":"organization.integrations.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","description":"Service of the channel: Microsoft Teams (Workflows webhook), Slack, Matrix, Discord or a generic webhook. New values can be added in later versions; handle unknown values.","x-extensible-enum":["teams","slack","matrix","discord","webhook"]},"name":{"type":"string","minLength":1,"maxLength":80,"description":"Name of the channel in Lunedo."},"events":{"minItems":1,"maxItems":7,"type":"array","items":{"type":"string","enum":["pagePublished","pageChanged","blogPostPublished","decisionRecorded","pageStatusChanged","commentCreated","announcementPublished"]},"description":"What is posted. Spaces: `pagePublished`, `pageChanged` (combined per hour), `blogPostPublished`, `decisionRecorded`, `pageStatusChanged`, `commentCreated`. Organizations: `announcementPublished`."},"target":{"anyOf":[{"type":"object","properties":{"url":{"type":"string","minLength":1,"maxLength":2000,"description":"Webhook address the service created. Stored encrypted and never returned."}},"required":["url"],"additionalProperties":false,"description":"For Teams, Slack, Discord and generic webhooks."},{"type":"object","properties":{"homeserver":{"type":"string","minLength":1,"maxLength":2000,"description":"Address of the Matrix homeserver."},"roomId":{"type":"string","minLength":1,"maxLength":500,"description":"Room as people see it in their client: an alias such as `#ops:example.org`, a matrix.to link or a room ID such as `!abc:example.org`. Aliases and links are resolved to the room ID when saving."},"accessToken":{"type":"string","minLength":1,"maxLength":2000,"description":"Access token of the bot account. Stored encrypted and never returned."}},"required":["homeserver","roomId","accessToken"],"additionalProperties":false,"description":"For Matrix."}],"description":"Where messages go. Private, loopback and link-local addresses are refused unless the instance allows them."}},"required":["kind","name","events","target"],"additionalProperties":false,"description":"The channel to connect."},"example":{"kind":"teams","name":"IT-Ops · General","events":["announcementPublished"],"target":{"url":"https://prod-12.westeurope.logic.azure.com/workflows/abc/triggers/manual/paths/invoke"}}}}},"responses":{"200":{"description":"Whether the service accepted it.","content":{"application/json":{"schema":{"type":"object","properties":{"delivered":{"type":"boolean","description":"Whether the service accepted the test message."},"failure":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Why the service did not accept messages. New values can be added in later versions; handle unknown values.","x-extensible-enum":["addressGone","unauthorized","rejected","unavailable","unreachable","blockedAddress","insecureAddress"]},"status":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"HTTP status the service answered with, if it answered."},"code":{"description":"Error code the service reported, such as `invalid_token`, if any.","type":["string","null"]}},"required":["reason","status","code"],"additionalProperties":false,"description":"Why a message was not delivered."},{"type":"null"}],"description":"Why it was not accepted, or null."}},"required":["delivered","failure"],"additionalProperties":false,"description":"Result of the test message."},"example":{"delivered":false,"failure":{"reason":"addressGone","status":404,"code":"no_service"}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `chatAddressBlocked`: The address points to a private network. `chatAddressInsecure`: The address needs HTTPS. `invalidChatAddress`: The address of the chat service is not valid. `invalidChatChannel`: The chat channel is not valid. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"chatAddressBlocked":{"value":{"type":"urn:lunedo:problem:chatAddressBlocked","title":"The address points to a private network","status":400,"code":"chatAddressBlocked"}},"chatAddressInsecure":{"value":{"type":"urn:lunedo:problem:chatAddressInsecure","title":"The address needs HTTPS","status":400,"code":"chatAddressInsecure"}},"invalidChatAddress":{"value":{"type":"urn:lunedo:problem:invalidChatAddress","title":"The address of the chat service is not valid","status":400,"code":"invalidChatAddress"}},"invalidChatChannel":{"value":{"type":"urn:lunedo:problem:invalidChatChannel","title":"The chat channel is not valid","status":400,"code":"invalidChatChannel"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`confidentialSpace`: Confidential spaces cannot post to chat channels. `tooManyChatChannels`: There are too many chat channels.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"confidentialSpace":{"value":{"type":"urn:lunedo:problem:confidentialSpace","title":"Confidential spaces cannot post to chat channels","status":409,"code":"confidentialSpace"}},"tooManyChatChannels":{"value":{"type":"urn:lunedo:problem:tooManyChatChannels","title":"There are too many chat channels","status":409,"code":"tooManyChatChannels"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/confidential-spaces":{"get":{"operationId":"confidentialSpaces.list","summary":"List confidential spaces","description":"Lists the confidential spaces of the organization with key, creation date, number of members and pages and last change. Names, members, titles and content stay hidden.\n\nRequires the permission `organization.spaces.view` on the organization in `organizationId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"organization.spaces.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"Confidential spaces, ordered by key.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"createdAt":{"type":"string","format":"date-time","description":"When the space was created. ISO 8601 timestamp in UTC."},"members":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people with a role."},"activeMembers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of members whose account is active."},"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of pages, without the trash."},"lastChangedAt":{"type":"string","format":"date-time","description":"Last change of the space or its content. ISO 8601 timestamp in UTC."},"needsAdministrator":{"type":"boolean","description":"True when no active space admin remains but other members do; one of them can be appointed."}},"required":["id","key","createdAt","members","activeMembers","pages","lastChangedAt","needsAdministrator"],"additionalProperties":false,"description":"A confidential space as organization administrators see it: no name, members or content."},"description":"Confidential spaces."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"One page of results."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5b00","key":"MSAB","createdAt":"2026-10-01T08:00:00.000Z","members":2,"activeMembers":1,"pages":12,"lastChangedAt":"2026-10-08T15:00:00.000Z","needsAdministrator":true}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/confidential-spaces/{spaceId}/administrator":{"post":{"operationId":"confidentialSpaces.appoint","summary":"Appoint a space admin of a confidential space","description":"Makes a remaining member space admin of a confidential space that has none. Never the caller and never someone who is not a member. The appointment is audited and the member is notified.\n\nRequires the permission `organization.spaces.manage` on the organization in `organizationId`. Needs a signed-in session; API tokens are refused.","tags":["Spaces"],"x-lunedo-permission":{"action":"organization.spaces.manage","resource":"organization","parameter":"organizationId"},"security":[{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"spaceId","in":"path","required":true,"description":"ID of the confidential space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"Remaining member who becomes space admin."}},"required":["accountId"],"additionalProperties":false,"description":"The new space admin."},"example":{"accountId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20"}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid. `selfAppointment`: Nobody can give themselves access this way.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"selfAppointment":{"value":{"type":"urn:lunedo:problem:selfAppointment","title":"Nobody can give themselves access this way","status":400,"code":"selfAppointment"}}}}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `reauthenticationRequired`: Confirm your identity first. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"reauthenticationRequired":{"value":{"type":"urn:lunedo:problem:reauthenticationRequired","title":"Confirm your identity first","status":403,"code":"reauthenticationRequired"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`spaceHasAdministrator`: The space has a space admin.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"spaceHasAdministrator":{"value":{"type":"urn:lunedo:problem:spaceHasAdministrator","title":"The space has a space admin","status":409,"code":"spaceHasAdministrator"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/confidential-spaces/{spaceId}/remaining-members":{"get":{"operationId":"confidentialSpaces.remaining","summary":"List the remaining members of a confidential space without space admin","description":"Lists only the names of the active members of a confidential space whose last space admin was deactivated, without the caller. The list is empty while the space has a space admin.\n\nRequires the permission `organization.spaces.manage` on the organization in `organizationId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"organization.spaces.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"spaceId","in":"path","required":true,"description":"ID of the confidential space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The remaining members.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false,"description":"A member."},"description":"Remaining members."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/discoverable-spaces":{"get":{"operationId":"accessRequests.discoverable","summary":"List spaces you can ask to join","description":"Lists the discoverable spaces of the organization that the caller cannot read yet.\n\nRequires the permission `organization.view` on the organization in `organizationId`.","tags":["Access requests"],"x-lunedo-permission":{"action":"organization.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The spaces.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"name":{"type":"string","description":"Name of the space."},"description":{"type":"string","description":"Description of the space."},"requested":{"type":"boolean","description":"Whether the caller has an open request for it."}},"required":["id","key","name","description","requested"],"additionalProperties":false,"description":"A space the caller can find and ask to join."},"description":"Spaces that can be found but not read, ordered by name."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a00","key":"ITOPS","name":"IT Operations","description":"Runbooks and on-call notes.","requested":false}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/domains":{"get":{"operationId":"organizations.domains","summary":"List domains","description":"Lists the e-mail domains of the organization. New accounts with these domains join it.\n\nRequires the permission `organization.signIn.view` on the organization in `organizationId`.","tags":["Organizations"],"x-lunedo-permission":{"action":"organization.signIn.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"Domains of the organization.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"domain":{"type":"string","description":"A domain of the organization."}},"required":["domain"],"additionalProperties":false,"description":"A domain."},"description":"Domains, in alphabetical order."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"One page of results."},"example":{"items":[{"domain":"example.org"}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"organizations.addDomain","summary":"Add a domain","description":"Assigns an e-mail domain to the organization. Each domain belongs to at most one organization.\n\nRequires the permission `instance.organizations.manage` on the instance.","tags":["Organizations"],"x-lunedo-permission":{"action":"instance.organizations.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","maxLength":253,"pattern":"^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z]{2,63}$","description":"Domain such as `example.org`. Each domain belongs to one organization."}},"required":["domain"],"additionalProperties":false,"description":"A domain to add."},"example":{"domain":"example.org"}}}},"responses":{"201":{"description":"The added domain, normalized.","content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","description":"A domain of the organization."}},"required":["domain"],"additionalProperties":false,"description":"A domain."},"example":{"domain":"example.org"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`domainTaken`: The domain belongs to another organization.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"domainTaken":{"value":{"type":"urn:lunedo:problem:domainTaken","title":"The domain belongs to another organization","status":409,"code":"domainTaken"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/domains/{domain}":{"delete":{"operationId":"organizations.removeDomain","summary":"Remove a domain","description":"Removes an e-mail domain from the organization.\n\nRequires the permission `instance.organizations.manage` on the instance.","tags":["Organizations"],"x-lunedo-permission":{"action":"instance.organizations.manage","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"domain","in":"path","required":true,"description":"The domain to remove.","schema":{"type":"string","maxLength":253,"pattern":"^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z]{2,63}$"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/embed-services":{"get":{"operationId":"embeds.list","summary":"List the services pages can embed","description":"Returns the external services whose content pages of the organization can embed: the instance allowlist, narrowed by the organization. Links to other addresses are shown as links.\n\nRequires the permission `organization.view` on the organization in `organizationId`.","tags":["Embeds"],"x-lunedo-permission":{"action":"organization.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The allowed services.","content":{"application/json":{"schema":{"type":"object","properties":{"services":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"ID of the service, such as `youtube`."},"name":{"type":"string","description":"Name of the service."},"rules":{"type":"array","items":{"type":"object","properties":{"pattern":{"type":"string","description":"Address pattern of a share link, an `https` address with placeholders such as `{video}` for one part of the address and `{*}` for any number of path segments."},"embed":{"type":"string","description":"Embed address built from the placeholders of the pattern; `{url}` stands for the whole link, encoded."},"referrerPolicy":{"description":"What the frame tells the service about the embedding page: `no-referrer` (default) sends nothing, `strict-origin` sends only the address of the instance.","type":"string","enum":["no-referrer","strict-origin"]}},"required":["pattern","embed"],"additionalProperties":false,"description":"How share links of a service become embed addresses."},"description":"Rules, tried in order."}},"required":["id","name","rules"],"additionalProperties":false,"description":"A service whose content pages can embed."},"description":"Services pages of the organization can embed, in the order they are tried."},"available":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"ID of the service, such as `youtube`."},"name":{"type":"string","description":"Name of the service."},"rules":{"type":"array","items":{"type":"object","properties":{"pattern":{"type":"string","description":"Address pattern of a share link, an `https` address with placeholders such as `{video}` for one part of the address and `{*}` for any number of path segments."},"embed":{"type":"string","description":"Embed address built from the placeholders of the pattern; `{url}` stands for the whole link, encoded."},"referrerPolicy":{"description":"What the frame tells the service about the embedding page: `no-referrer` (default) sends nothing, `strict-origin` sends only the address of the instance.","type":"string","enum":["no-referrer","strict-origin"]}},"required":["pattern","embed"],"additionalProperties":false,"description":"How share links of a service become embed addresses."},"description":"Rules, tried in order."}},"required":["id","name","rules"],"additionalProperties":false,"description":"A service whose content pages can embed."},"description":"All services of the instance allowlist. The organization can narrow its list to some of them."},"narrowed":{"type":"boolean","description":"Whether the organization narrowed the instance allowlist."}},"required":["services","available","narrowed"],"additionalProperties":false,"description":"Services whose content pages of the organization can embed."},"example":{"services":[{"id":"youtube","name":"YouTube","rules":[{"pattern":"https://www.youtube.com/watch?v={video}","embed":"https://www.youtube-nocookie.com/embed/{video}","referrerPolicy":"strict-origin"},{"pattern":"https://www.youtube.com/embed/{video}","embed":"https://www.youtube-nocookie.com/embed/{video}","referrerPolicy":"strict-origin"},{"pattern":"https://www.youtube.com/shorts/{video}","embed":"https://www.youtube-nocookie.com/embed/{video}","referrerPolicy":"strict-origin"},{"pattern":"https://youtube.com/watch?v={video}","embed":"https://www.youtube-nocookie.com/embed/{video}","referrerPolicy":"strict-origin"},{"pattern":"https://youtube.com/embed/{video}","embed":"https://www.youtube-nocookie.com/embed/{video}","referrerPolicy":"strict-origin"},{"pattern":"https://youtube.com/shorts/{video}","embed":"https://www.youtube-nocookie.com/embed/{video}","referrerPolicy":"strict-origin"},{"pattern":"https://m.youtube.com/watch?v={video}","embed":"https://www.youtube-nocookie.com/embed/{video}","referrerPolicy":"strict-origin"},{"pattern":"https://m.youtube.com/embed/{video}","embed":"https://www.youtube-nocookie.com/embed/{video}","referrerPolicy":"strict-origin"},{"pattern":"https://m.youtube.com/shorts/{video}","embed":"https://www.youtube-nocookie.com/embed/{video}","referrerPolicy":"strict-origin"},{"pattern":"https://youtu.be/{video}","embed":"https://www.youtube-nocookie.com/embed/{video}","referrerPolicy":"strict-origin"},{"pattern":"https://www.youtube-nocookie.com/embed/{video}","embed":"https://www.youtube-nocookie.com/embed/{video}","referrerPolicy":"strict-origin"}]}],"available":[{"id":"youtube","name":"YouTube","rules":[{"pattern":"https://www.youtube.com/watch?v={video}","embed":"https://www.youtube-nocookie.com/embed/{video}","referrerPolicy":"strict-origin"},{"pattern":"https://www.youtube.com/embed/{video}","embed":"https://www.youtube-nocookie.com/embed/{video}","referrerPolicy":"strict-origin"},{"pattern":"https://www.youtube.com/shorts/{video}","embed":"https://www.youtube-nocookie.com/embed/{video}","referrerPolicy":"strict-origin"},{"pattern":"https://youtube.com/watch?v={video}","embed":"https://www.youtube-nocookie.com/embed/{video}","referrerPolicy":"strict-origin"},{"pattern":"https://youtube.com/embed/{video}","embed":"https://www.youtube-nocookie.com/embed/{video}","referrerPolicy":"strict-origin"},{"pattern":"https://youtube.com/shorts/{video}","embed":"https://www.youtube-nocookie.com/embed/{video}","referrerPolicy":"strict-origin"},{"pattern":"https://m.youtube.com/watch?v={video}","embed":"https://www.youtube-nocookie.com/embed/{video}","referrerPolicy":"strict-origin"},{"pattern":"https://m.youtube.com/embed/{video}","embed":"https://www.youtube-nocookie.com/embed/{video}","referrerPolicy":"strict-origin"},{"pattern":"https://m.youtube.com/shorts/{video}","embed":"https://www.youtube-nocookie.com/embed/{video}","referrerPolicy":"strict-origin"},{"pattern":"https://youtu.be/{video}","embed":"https://www.youtube-nocookie.com/embed/{video}","referrerPolicy":"strict-origin"},{"pattern":"https://www.youtube-nocookie.com/embed/{video}","embed":"https://www.youtube-nocookie.com/embed/{video}","referrerPolicy":"strict-origin"}]},{"id":"vimeo","name":"Vimeo","rules":[{"pattern":"https://vimeo.com/{video}","embed":"https://player.vimeo.com/video/{video}?dnt=1"},{"pattern":"https://vimeo.com/{video}/{hash}","embed":"https://player.vimeo.com/video/{video}?h={hash}&dnt=1"},{"pattern":"https://player.vimeo.com/video/{video}","embed":"https://player.vimeo.com/video/{video}?dnt=1"}]}],"narrowed":true}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/groups":{"get":{"operationId":"organizations.groups","summary":"List groups","description":"Lists the groups of the organization.\n\nRequires the permission `organization.groups.view` on the organization in `organizationId`.","tags":["Groups"],"x-lunedo-permission":{"action":"organization.groups.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}},{"name":"q","in":"query","required":false,"description":"Only items that contain this text, ignoring case: in the name and e-mail address of accounts and members, the name and short name of organizations, and the name and description of groups.","schema":{"type":"string","maxLength":200}}],"responses":{"200":{"description":"Groups of the organization.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the group."},"organizationId":{"type":"string","format":"uuid","description":"ID of the organization the group belongs to."},"name":{"type":"string","description":"Name of the group, unique in the organization, 1 to 100 characters."},"description":{"type":"string","description":"Description, up to 1000 characters."},"managedBy":{"description":"The identity provider that manages the members of a synchronized group, or null. Members of such a group cannot be changed in Lunedo; its permissions can.","anyOf":[{"type":"object","properties":{"providerId":{"type":"string","format":"uuid","description":"ID of the identity provider."},"providerName":{"type":"string","description":"Name of the identity provider."}},"required":["providerId","providerName"],"additionalProperties":false},{"type":"null"}]},"formerlySynchronizedFrom":{"description":"Name of the removed identity provider this group was synchronized from, or null. Such a group is an ordinary group now.","type":["string","null"]},"memberCount":{"description":"Number of active accounts in the group. Only in lists of groups.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"spaceCount":{"description":"Number of spaces that give the group a role. Only in lists of groups.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","organizationId","name","description"],"additionalProperties":false,"description":"A group of accounts."},"description":"Groups, ordered by name."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"One page of results."},"example":{"items":[{"id":"01929b1f-0a6d-7a51-827e-6f5a4b3c8d9e","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","name":"Editors","description":"Everyone who edits the handbook"}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"organizations.createGroup","summary":"Create a group","description":"Creates a group. The creator becomes its manager.\n\nRequires the permission `organization.groups.create` on the organization in `organizationId`.","tags":["Groups"],"x-lunedo-permission":{"action":"organization.groups.create","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Name of the group, 1 to 100 characters, unique in the organization."},"description":{"description":"Description, up to 1000 characters.","type":"string","maxLength":1000}},"required":["name"],"additionalProperties":false,"description":"A new group."},"example":{"name":"Editors","description":"Everyone who edits the handbook"}}}},"responses":{"201":{"description":"The new group.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the group."},"organizationId":{"type":"string","format":"uuid","description":"ID of the organization the group belongs to."},"name":{"type":"string","description":"Name of the group, unique in the organization, 1 to 100 characters."},"description":{"type":"string","description":"Description, up to 1000 characters."},"managedBy":{"description":"The identity provider that manages the members of a synchronized group, or null. Members of such a group cannot be changed in Lunedo; its permissions can.","anyOf":[{"type":"object","properties":{"providerId":{"type":"string","format":"uuid","description":"ID of the identity provider."},"providerName":{"type":"string","description":"Name of the identity provider."}},"required":["providerId","providerName"],"additionalProperties":false},{"type":"null"}]},"formerlySynchronizedFrom":{"description":"Name of the removed identity provider this group was synchronized from, or null. Such a group is an ordinary group now.","type":["string","null"]},"memberCount":{"description":"Number of active accounts in the group. Only in lists of groups.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"spaceCount":{"description":"Number of spaces that give the group a role. Only in lists of groups.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","organizationId","name","description"],"additionalProperties":false,"description":"A group of accounts."},"example":{"id":"01929b1f-0a6d-7a51-827e-6f5a4b3c8d9e","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","name":"Editors","description":"Everyone who edits the handbook"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`groupNameTaken`: The group name is taken.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"groupNameTaken":{"value":{"type":"urn:lunedo:problem:groupNameTaken","title":"The group name is taken","status":409,"code":"groupNameTaken"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/help":{"get":{"operationId":"portal.help","summary":"Where the help icon leads","description":"The knowledge base the help icon of the app opens, and the knowledge bases that can be chosen.\n\nRequires the permission `organization.view` on the organization in `organizationId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"organization.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The help target.","content":{"application/json":{"schema":{"type":"object","properties":{"current":{"anyOf":[{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"ID of the knowledge base."},"name":{"type":"string","description":"Name of the knowledge base."},"url":{"type":"string","description":"Address of its portal."}},"required":["spaceId","name","url"],"additionalProperties":false,"description":"A knowledge base the help icon can open."},{"type":"null"}],"description":"The chosen knowledge base, or null for the Lunedo documentation."},"candidates":{"type":"array","items":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"ID of the knowledge base."},"name":{"type":"string","description":"Name of the knowledge base."},"url":{"type":"string","description":"Address of its portal."}},"required":["spaceId","name","url"],"additionalProperties":false,"description":"A knowledge base the help icon can open."},"description":"Knowledge bases everyone signed in may read."}},"required":["current","candidates"],"additionalProperties":false,"description":"Where the help icon of the app leads."},"example":{"current":null,"candidates":[]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"put":{"operationId":"portal.setHelp","summary":"Choose where the help icon leads","description":"Points the help icon of the app to a knowledge base of the organization that everyone signed in may read, or back to the Lunedo documentation with null.\n\nRequires the permission `organization.settings.manage` on the organization in `organizationId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"organization.settings.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the knowledge base."}},"required":["spaceId"],"additionalProperties":false,"description":"The knowledge base, or null for the Lunedo documentation."},"example":{"spaceId":null}}}},"responses":{"200":{"description":"The help target.","content":{"application/json":{"schema":{"type":"object","properties":{"current":{"anyOf":[{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"ID of the knowledge base."},"name":{"type":"string","description":"Name of the knowledge base."},"url":{"type":"string","description":"Address of its portal."}},"required":["spaceId","name","url"],"additionalProperties":false,"description":"A knowledge base the help icon can open."},{"type":"null"}],"description":"The chosen knowledge base, or null for the Lunedo documentation."},"candidates":{"type":"array","items":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"ID of the knowledge base."},"name":{"type":"string","description":"Name of the knowledge base."},"url":{"type":"string","description":"Address of its portal."}},"required":["spaceId","name","url"],"additionalProperties":false,"description":"A knowledge base the help icon can open."},"description":"Knowledge bases everyone signed in may read."}},"required":["current","candidates"],"additionalProperties":false,"description":"Where the help icon of the app leads."},"example":{"current":null,"candidates":[]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidHelpKnowledgeBase`: The knowledge base cannot be the help target. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidHelpKnowledgeBase":{"value":{"type":"urn:lunedo:problem:invalidHelpKnowledgeBase","title":"The knowledge base cannot be the help target","status":400,"code":"invalidHelpKnowledgeBase"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/home-page":{"get":{"operationId":"home.organizationHomePage","summary":"Get the organization home page","description":"Returns the page organization admins chose as home page, if the caller can read it.\n\nRequires the permission `organization.view` on the organization in `organizationId`.","tags":["Home"],"x-lunedo-permission":{"action":"organization.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The home page.","content":{"application/json":{"schema":{"type":"object","properties":{"page":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the page or blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app."},"kind":{"type":"string","description":"Kind of the item. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title readers see."},"spaceId":{"type":"string","format":"uuid","description":"Space of the item."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."},"mySpace":{"type":"boolean","description":"Whether the item lies in the caller's own personal space."}},"required":["id","number","kind","title","spaceId","spaceKey","spaceName","mySpace"],"additionalProperties":false,"description":"A page or blog post."},{"type":"null"}],"description":"The organization home page, or null when none is set or the caller cannot read it."}},"required":["page"],"additionalProperties":false,"description":"The organization home page."},"example":{"page":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"kind":"page","title":"VPN access for remote staff","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","mySpace":false}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"put":{"operationId":"home.setOrganizationHomePage","summary":"Set the organization home page","description":"Chooses an existing page of a space of the organization as its home page, or none. Members choose in their preferences whether they land there after sign-in. The change is recorded in the audit log.\n\nRequires the permission `organization.settings.manage` on the organization in `organizationId`.","tags":["Home"],"x-lunedo-permission":{"action":"organization.settings.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"A page in a space of the organization, or null for none."}},"required":["itemId"],"additionalProperties":false,"description":"The new organization home page."},"example":{"itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40"}}}},"responses":{"200":{"description":"The new home page.","content":{"application/json":{"schema":{"type":"object","properties":{"page":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the page or blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app."},"kind":{"type":"string","description":"Kind of the item. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title readers see."},"spaceId":{"type":"string","format":"uuid","description":"Space of the item."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."},"mySpace":{"type":"boolean","description":"Whether the item lies in the caller's own personal space."}},"required":["id","number","kind","title","spaceId","spaceKey","spaceName","mySpace"],"additionalProperties":false,"description":"A page or blog post."},{"type":"null"}],"description":"The organization home page, or null when none is set or the caller cannot read it."}},"required":["page"],"additionalProperties":false,"description":"The organization home page."},"example":{"page":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"kind":"page","title":"VPN access for remote staff","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","mySpace":false}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidHomePage`: The page cannot be the organization home page. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidHomePage":{"value":{"type":"urn:lunedo:problem:invalidHomePage","title":"The page cannot be the organization home page","status":400,"code":"invalidHomePage"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/import-folder":{"get":{"operationId":"imports.folder","summary":"List the import folder","description":"Lists the regular files directly inside this organization's subfolder of the import folder on the server, named after the organization's slug. Symbolic links, hidden files and further subfolders are left out; files of other organizations and at the top level are never offered.\n\nRequires the permission `organization.imports.manage` on the organization in `organizationId`.","tags":["Imports"],"x-lunedo-permission":{"action":"organization.imports.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The files.","content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether the instance allows imports from the import folder."},"path":{"type":"string","description":"Folder on the server for this organization's exports: the subfolder named after the organization's slug inside the import folder. It changes when the slug changes."},"files":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the file."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size in bytes."},"modifiedAt":{"type":"string","format":"date-time","description":"When the file last changed. ISO 8601 timestamp in UTC."}},"required":["name","size","modifiedAt"],"additionalProperties":false,"description":"A file in the import folder."},"description":"Regular files directly inside this organization's subfolder of the import folder."},"maxUploadBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Largest file that can be uploaded from the browser; instance administrators can raise it, or larger exports go through the import folder."}},"required":["enabled","path","files","maxUploadBytes"],"additionalProperties":false,"description":"Files in this organization's subfolder of the import folder."},"example":{"enabled":true,"path":"/data/import/acme","files":[{"name":"export.zip","size":6871947673,"modifiedAt":"2026-10-09T18:00:00.000Z"}],"maxUploadBytes":2147483648}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`importFolderUnavailable`: The import folder cannot be read.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"importFolderUnavailable":{"value":{"type":"urn:lunedo:problem:importFolderUnavailable","title":"The import folder cannot be read","status":409,"code":"importFolderUnavailable"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/import-uploads":{"post":{"operationId":"imports.createUpload","summary":"Start an upload","description":"Starts uploading an export in parts. Files above the upload limit of the instance are refused before any part is sent; use the import folder for them. An upload that no import uses is deleted after 7 days.\n\nRequires the permission `organization.imports.manage` on the organization in `organizationId`.","tags":["Imports"],"x-lunedo-permission":{"action":"organization.imports.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":1000,"description":"Name of the file."},"size":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Size of the file in bytes."}},"required":["name","size"],"additionalProperties":false,"description":"A new upload."},"example":{"name":"export.zip","size":20971520}}}},"responses":{"201":{"description":"The upload.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the upload."},"name":{"type":"string","description":"Name of the file."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the whole file in bytes."},"partSize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of every part but the last in bytes."},"partCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of parts."},"parts":{"type":"array","items":{"type":"object","properties":{"number":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the part."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size in bytes."}},"required":["number","size"],"additionalProperties":false,"description":"A part the server stored."},"description":"Parts already stored, for continuing an interrupted upload."},"complete":{"type":"boolean","description":"Whether all parts arrived and the checksum matched."},"expiresAt":{"type":"string","format":"date-time","description":"When the upload is deleted unless an import uses it. ISO 8601 timestamp in UTC."}},"required":["id","name","size","partSize","partCount","parts","complete","expiresAt"],"additionalProperties":false,"description":"An upload of an export in parts."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0004","name":"export.zip","size":20971520,"partSize":16777216,"partCount":2,"parts":[],"complete":false,"expiresAt":"2026-10-17T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidFileName`: The file name is not valid. `invalidInput`: The request is not valid. `invalidUpload`: The upload is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidFileName":{"value":{"type":"urn:lunedo:problem:invalidFileName","title":"The file name is not valid","status":400,"code":"invalidFileName"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidUpload":{"value":{"type":"urn:lunedo:problem:invalidUpload","title":"The upload is not valid","status":400,"code":"invalidUpload"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`organizationImportLimit`: The imports of the organization reached their limit.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"organizationImportLimit":{"value":{"type":"urn:lunedo:problem:organizationImportLimit","title":"The imports of the organization reached their limit","status":409,"code":"organizationImportLimit"}}}}}},"413":{"description":"`uploadTooLarge`: The file is larger than uploads allow.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"uploadTooLarge":{"value":{"type":"urn:lunedo:problem:uploadTooLarge","title":"The file is larger than uploads allow","status":413,"code":"uploadTooLarge"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}},"507":{"description":"`storageFull`: Storage is almost full.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"storageFull":{"value":{"type":"urn:lunedo:problem:storageFull","title":"Storage is almost full","status":507,"code":"storageFull"}}}}}}}}},"/api/v1/organizations/{organizationId}/import-uploads/{uploadId}":{"delete":{"operationId":"imports.removeUpload","summary":"Delete an upload","description":"Deletes an upload that no started import uses.\n\nRequires the permission `organization.imports.manage` on the organization in `organizationId`.","tags":["Imports"],"x-lunedo-permission":{"action":"organization.imports.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"uploadId","in":"path","required":true,"description":"ID of the upload.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"get":{"operationId":"imports.getUpload","summary":"Get an upload","description":"Returns the upload with the parts already stored, to continue after a lost connection.\n\nRequires the permission `organization.imports.manage` on the organization in `organizationId`.","tags":["Imports"],"x-lunedo-permission":{"action":"organization.imports.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"uploadId","in":"path","required":true,"description":"ID of the upload.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The upload.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the upload."},"name":{"type":"string","description":"Name of the file."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the whole file in bytes."},"partSize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of every part but the last in bytes."},"partCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of parts."},"parts":{"type":"array","items":{"type":"object","properties":{"number":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the part."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size in bytes."}},"required":["number","size"],"additionalProperties":false,"description":"A part the server stored."},"description":"Parts already stored, for continuing an interrupted upload."},"complete":{"type":"boolean","description":"Whether all parts arrived and the checksum matched."},"expiresAt":{"type":"string","format":"date-time","description":"When the upload is deleted unless an import uses it. ISO 8601 timestamp in UTC."}},"required":["id","name","size","partSize","partCount","parts","complete","expiresAt"],"additionalProperties":false,"description":"An upload of an export in parts."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0004","name":"export.zip","size":20971520,"partSize":16777216,"partCount":2,"parts":[{"number":1,"size":16777216}],"complete":false,"expiresAt":"2026-10-17T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/import-uploads/{uploadId}/complete":{"post":{"operationId":"imports.completeUpload","summary":"Complete an upload","description":"Checks that all parts arrived, reads them again and compares the checksum with the one of the file the caller sent.\n\nRequires the permission `organization.imports.manage` on the organization in `organizationId`.","tags":["Imports"],"x-lunedo-permission":{"action":"organization.imports.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"uploadId","in":"path","required":true,"description":"ID of the upload.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sha256":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"SHA-256 over the hexadecimal SHA-256 values of all parts, joined in order. The server reads every stored part again and compares."}},"required":["sha256"],"additionalProperties":false,"description":"Completion of an upload."},"example":{"sha256":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"}}}},"responses":{"200":{"description":"The complete upload.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the upload."},"name":{"type":"string","description":"Name of the file."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the whole file in bytes."},"partSize":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of every part but the last in bytes."},"partCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of parts."},"parts":{"type":"array","items":{"type":"object","properties":{"number":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the part."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size in bytes."}},"required":["number","size"],"additionalProperties":false,"description":"A part the server stored."},"description":"Parts already stored, for continuing an interrupted upload."},"complete":{"type":"boolean","description":"Whether all parts arrived and the checksum matched."},"expiresAt":{"type":"string","format":"date-time","description":"When the upload is deleted unless an import uses it. ISO 8601 timestamp in UTC."}},"required":["id","name","size","partSize","partCount","parts","complete","expiresAt"],"additionalProperties":false,"description":"An upload of an export in parts."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0004","name":"export.zip","size":20971520,"partSize":16777216,"partCount":2,"parts":[{"number":1,"size":16777216}],"complete":true,"expiresAt":"2026-10-17T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `uploadChecksumMismatch`: The uploaded data does not match its checksum.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"uploadChecksumMismatch":{"value":{"type":"urn:lunedo:problem:uploadChecksumMismatch","title":"The uploaded data does not match its checksum","status":400,"code":"uploadChecksumMismatch"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`uploadIncomplete`: The upload is not complete.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"uploadIncomplete":{"value":{"type":"urn:lunedo:problem:uploadIncomplete","title":"The upload is not complete","status":409,"code":"uploadIncomplete"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/import-uploads/{uploadId}/parts/{number}":{"put":{"operationId":"imports.putPart","summary":"Upload a part","description":"Stores one part. Send the bytes with `Content-Type: application/octet-stream`. Every part except the last has the part size of the upload. Sending a part again replaces it.\n\nRequires the permission `organization.imports.manage` on the organization in `organizationId`.","tags":["Imports"],"x-lunedo-permission":{"action":"organization.imports.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"uploadId","in":"path","required":true,"description":"ID of the upload.","schema":{"type":"string","format":"uuid"}},{"name":"number","in":"path","required":true,"description":"Number of the part, starting at 1.","schema":{"type":"integer","minimum":1,"maximum":100000}},{"name":"sha256","in":"query","required":true,"description":"SHA-256 of the part in hexadecimal. The server refuses the part when it does not match.","schema":{"type":"string","pattern":"^[0-9a-f]{64}$"}}],"requestBody":{"required":true,"description":"The bytes of the part.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"The stored part.","content":{"application/json":{"schema":{"type":"object","properties":{"number":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the part."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size in bytes."}},"required":["number","size"],"additionalProperties":false,"description":"A stored part."},"example":{"number":1,"size":16777216}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidUploadPart`: The part of the upload is not valid. `uploadChecksumMismatch`: The uploaded data does not match its checksum.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidUploadPart":{"value":{"type":"urn:lunedo:problem:invalidUploadPart","title":"The part of the upload is not valid","status":400,"code":"invalidUploadPart"}},"uploadChecksumMismatch":{"value":{"type":"urn:lunedo:problem:uploadChecksumMismatch","title":"The uploaded data does not match its checksum","status":400,"code":"uploadChecksumMismatch"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`uploadComplete`: The upload is already complete.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"uploadComplete":{"value":{"type":"urn:lunedo:problem:uploadComplete","title":"The upload is already complete","status":409,"code":"uploadComplete"}}}}}},"415":{"description":"`unsupportedMediaType`: The request body has an unsupported type.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unsupportedMediaType":{"value":{"type":"urn:lunedo:problem:unsupportedMediaType","title":"The request body has an unsupported type","status":415,"code":"unsupportedMediaType"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}},"507":{"description":"`storageFull`: Storage is almost full.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"storageFull":{"value":{"type":"urn:lunedo:problem:storageFull","title":"Storage is almost full","status":507,"code":"storageFull"}}}}}}}}},"/api/v1/organizations/{organizationId}/imports":{"get":{"operationId":"imports.list","summary":"List imports","description":"Lists the imports of the organization the caller runs or reviews, and imports that wait for another administrator to take over. Drafts are visible only to their importer.\n\nRequires the permission `organization.view` on the organization in `organizationId`.","tags":["Imports"],"x-lunedo-permission":{"action":"organization.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The imports.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the import."},"organizationId":{"type":"string","format":"uuid","description":"Organization the import belongs to."},"importer":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"The administrator who imports."},"source":{"type":"string","description":"What is imported: `confluence-xml` for the XML space export of Confluence Cloud or Data Center, `confluence-csv` for the CSV space export of Confluence Cloud, `confluence-cloud` and `confluence-dc` to read a space through the Confluence API, `markdown` for a ZIP file of Markdown files, `word` for Word documents (`.docx`). New values can be added in later versions; handle unknown values.","x-extensible-enum":["confluence-xml","confluence-csv","confluence-cloud","confluence-dc","markdown","word"]},"state":{"type":"string","description":"State of the import. `draft` while the wizard is filled in, `analyzing` while the export is read, `ready` when it can be started, `running` while it imports, `held` when the importing administrator lost the permission and another administrator has to take over, `stopping` and `discarding` while the quarantine space is deleted, `review` when the quarantine space waits for a decision, `accepted`, `discarded`, `stopped` and `failed` at the end. A re-import is in `running` while it compares or applies, in `review` while changes wait for a decision, `accepted` when everything is applied, and `superseded` when a newer re-import of the same space replaced it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["draft","analyzing","ready","running","held","stopping","review","accepting","accepted","discarding","discarded","stopped","failed","superseded"]},"draftStep":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Step of the wizard the importer was on, for continuing a draft."},"file":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Where the export comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload","folder"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes, or null when not known yet."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload, or null for a file in the import folder."},"complete":{"type":"boolean","description":"Whether the file is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},{"type":"null"}],"description":"The export file, or null when none is chosen yet."},"spaceName":{"description":"Name of the new space.","type":["string","null"]},"spaceKey":{"description":"Key of the new space.","type":["string","null"]},"archived":{"type":"boolean","description":"Whether the space becomes archived when the import is accepted."},"history":{"type":"boolean","description":"Whether every Confluence version becomes a Lunedo version, or only the current state is imported."},"peopleSource":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"How people are recognized: `token` reads names and e-mail addresses with a read-only Atlassian API token, `list` uses a user list exported from the Atlassian administration, `skip` keeps every author as a placeholder, `source` takes the names Confluence Data Center returns through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["token","list","skip","source"]},"site":{"description":"Confluence site the token is used with, or null.","type":["string","null"]},"email":{"description":"Atlassian e-mail address the token belongs to, or null.","type":["string","null"]},"people":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"People of the export the token could read, or people in the user list; null when unknown."},"withEmail":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Of these, people with a visible e-mail address."}},"required":["kind","site","email","people","withEmail"],"additionalProperties":false},{"type":"null"}],"description":"How people are recognized. The token itself is never returned."},"connection":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Kind of Confluence the import reads through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["cloud","dataCenter"]},"site":{"type":"string","description":"Host name of the Confluence site, with the port when it is not 443."},"basePath":{"type":"string","description":"Context path of Confluence Data Center, such as `/confluence`, or empty."},"email":{"description":"Atlassian e-mail address the API token belongs to, or null.","type":["string","null"]},"account":{"description":"Name of the Confluence account the token belongs to.","type":["string","null"]},"selection":{"type":"array","items":{"type":"object","properties":{"importId":{"type":"string","format":"uuid","description":"ID of the import that reads the space."},"spaceKey":{"type":"string","description":"Key of the Confluence space."}},"required":["importId","spaceKey"],"additionalProperties":false},"description":"Spaces chosen with this connection whose imports are not started yet, one import per space, this import included. Empty once the import has started."}},"required":["kind","site","basePath","email","account","selection"],"additionalProperties":false},{"type":"null"}],"description":"The connection of an import through the Confluence API, or null. Several imports of the same importer can share one connection; the token is never returned."},"files":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","description":"Where the document comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload."},"complete":{"type":"boolean","description":"Whether the upload is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},"description":"The Word documents of a `word` import, in their order. Empty for other imports."},"options":{"type":"object","properties":{"spaceKey":{"description":"Key of the Confluence space read through the API or from a site backup.","type":"string"},"pageIds":{"description":"IDs of the top-level pages whose trees are imported; all pages when left out.","type":"array","items":{"type":"string"}},"blogPosts":{"description":"Whether blog posts are imported; true when left out.","type":"boolean"},"split":{"type":"string","description":"`file` makes each Word document one page, `heading` adds a subpage per top-level heading. New values can be added in later versions; handle unknown values.","x-extensible-enum":["file","heading"]},"knowledgeBase":{"description":"For a `markdown` import: whether the new space is a knowledge base.","type":"boolean"}},"additionalProperties":false,"description":"Options of the source."},"throttledUntil":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Until when Confluence asked Lunedo to slow down, or null. The import continues by itself. ISO 8601 timestamp in UTC."},"waitingFor":{"description":"Key of the Confluence space whose import over the same connection reads or runs first, or null. Imports sharing a connection run one after another; this one continues by itself.","type":["string","null"]},"tokenDeletedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the API token was deleted: when the import was accepted, discarded, stopped or failed, when the importer lost the permission to import, or when the draft was left alone for a week. ISO 8601 timestamp in UTC."},"sourceUrl":{"description":"Address of the Confluence site. Links to pages outside the export point there.","type":["string","null"]},"reviewers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"People who can read the quarantine space and the report."},"phase":{"anyOf":[{"type":"string","x-extensible-enum":["read","compare","space","people","pages","attachments","templates","content","comments","reactions","permissions","baseline","finish","lineage","moves","labels","deletions","done"]},{"type":"null"}],"description":"Step the import is in: `read` reads the export, then `space`, `people`, `pages`, `attachments`, `templates`, `content`, `comments`, `reactions`, `permissions`, `baseline` and `finish`; `done` after the last step. A re-import compares in `compare` and applies in `lineage`, `people`, `pages`, `moves`, `attachments`, `templates`, `content`, `labels`, `comments`, `reactions`, `deletions`, `baseline` and `finish`. New values can be added in later versions; handle unknown values."},"progress":{"type":"object","properties":{"done":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units done in the current step."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units of the current step, or 0 when not known."}},"required":["done","total"],"additionalProperties":false,"description":"Progress of the current step."},"found":{"anyOf":[{"type":"object","properties":{"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages in the export."},"blogPosts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Blog posts in the export."},"versions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Earlier versions of pages and blog posts."},"comments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Comments, including inline comments and replies."},"likes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Likes on pages, blog posts and comments."},"watchers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Watchers of pages and the space. They are counted, not imported."},"attachments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Attachments of these pages."},"attachmentBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the current attachment versions in bytes."},"people":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"People named in the export."},"macroKinds":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Different macros used on the pages."},"spaceKey":{"type":"string","description":"Key of the space in Confluence."},"spaceName":{"type":"string","description":"Name of the space in Confluence."}},"required":["pages","blogPosts","versions","comments","likes","watchers","attachments","attachmentBytes","people","macroKinds","spaceKey","spaceName"],"additionalProperties":false},{"type":"null"}],"description":"What the export contains, once it was read."},"sourceSpaces":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the space in Confluence."},"name":{"type":"string","description":"Name of the space in Confluence."}},"required":["key","name"],"additionalProperties":false}},{"type":"null"}],"description":"The spaces of a site backup, once it was read; choose one with `options.spaceKey`. Null for exports and backups of one space."},"counts":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"What was imported, by kind: `pages`, `blogPosts`, `versions`, `attachments`, `attachmentVersions`, `comments`, `inlineAnchored`, `inlineMoved`, `likes`, `watchers`, `people`, `peopleMatched`, `restrictions`, `groupsMissing` and `problems`."},"errorCode":{"description":"Why the export could not be read or the import failed, such as `notAnArchive`, `wrongFormat`, `archiveTooLarge`, `unsafeEntryName`, `xmlDeclaration`, `spaceChoiceRequired` (a site backup with several spaces; see `sourceSpaces`) or `internalError`.","type":["string","null"]},"quarantineSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."}},"required":["id","key"],"additionalProperties":false},{"type":"null"}],"description":"The space the import writes into."},"targetSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"name":{"type":"string","description":"Name of the space."}},"required":["id","key","name"],"additionalProperties":false},{"type":"null"}],"description":"For a re-import, the space created by the earlier import that the changes go into; otherwise null."},"reimportSpaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space a newer export of the same Confluence space can be imported into again, or null when this import offers no re-import."},"canManage":{"type":"boolean","description":"Whether the caller can change, start, stop, accept or discard the import."},"canResolve":{"type":"boolean","description":"Whether the caller can map people and groups of the import or apply a user list."},"canTakeOver":{"type":"boolean","description":"Whether the caller can take over a held import."},"startedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import finished or failed. ISO 8601 timestamp in UTC."},"decidedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import was accepted, discarded or stopped. ISO 8601 timestamp in UTC."},"fileExpiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When an uploaded file is deleted. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the import was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the import last changed. ISO 8601 timestamp in UTC."}},"required":["id","organizationId","importer","source","state","draftStep","file","spaceName","spaceKey","archived","history","peopleSource","connection","files","options","throttledUntil","waitingFor","tokenDeletedAt","sourceUrl","reviewers","phase","progress","found","sourceSpaces","counts","errorCode","quarantineSpace","targetSpace","reimportSpaceId","canManage","canResolve","canTakeOver","startedAt","finishedAt","decidedAt","fileExpiresAt","createdAt","updatedAt"],"additionalProperties":false,"description":"An import of a Confluence space."},"description":"Imports, newest first."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0001","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0002","importer":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0003","name":"Alex Admin"},"source":"confluence-xml","state":"review","draftStep":3,"file":{"kind":"upload","name":"export.zip","size":1048576,"uploadId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0004","complete":true},"spaceName":"IT Operations","spaceKey":"ITOPS","archived":false,"sourceUrl":"https://example.atlassian.net/wiki","reviewers":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0005","name":"Robin Reviewer"}],"phase":null,"progress":{"done":0,"total":0},"found":{"pages":120,"blogPosts":6,"versions":340,"comments":85,"likes":30,"watchers":44,"attachments":40,"attachmentBytes":2048000,"people":12,"macroKinds":6,"spaceKey":"ITOPS","spaceName":"IT Operations"},"sourceSpaces":null,"history":false,"peopleSource":{"kind":"token","site":"example.atlassian.net","email":"alex@example.com","people":12,"withEmail":10},"connection":null,"files":[],"options":{},"throttledUntil":null,"waitingFor":null,"tokenDeletedAt":null,"counts":{"pages":120,"blogPosts":6,"attachments":40,"attachmentVersions":52,"comments":85,"people":12,"problems":7},"errorCode":null,"quarantineSpace":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0006","key":"ITOPS"},"targetSpace":null,"reimportSpaceId":null,"canManage":true,"canResolve":true,"canTakeOver":false,"startedAt":"2026-10-10T08:00:00.000Z","finishedAt":"2026-10-10T08:05:00.000Z","decidedAt":null,"fileExpiresAt":null,"createdAt":"2026-10-10T07:50:00.000Z","updatedAt":"2026-10-10T08:05:00.000Z"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"imports.create","summary":"Start an import draft","description":"Creates a draft of an import into a new space. The draft is saved as it is filled in and can be continued later. Importing needs the organization area spaces at manage, and API tokens the organization scope spaces at manage.\n\nRequires the permission `organization.imports.manage` on the organization in `organizationId`.","tags":["Imports"],"x-lunedo-permission":{"action":"organization.imports.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"source":{"type":"string","description":"What is imported: `confluence-xml` for the XML space export of Confluence Cloud or Data Center, `confluence-csv` for the CSV space export of Confluence Cloud, `confluence-cloud` and `confluence-dc` to read a space through the Confluence API, `markdown` for a ZIP file of Markdown files, `word` for Word documents (`.docx`). New values can be added in later versions; handle unknown values.","x-extensible-enum":["confluence-xml","confluence-csv","confluence-cloud","confluence-dc","markdown","word"]},"spaceId":{"type":"string","format":"uuid","description":"For a re-import: the space an earlier import created from the same Confluence space. Leave it out for an import into a new space."}},"required":["source"],"additionalProperties":false,"description":"A new import draft."},"example":{"source":"confluence-xml"}}}},"responses":{"201":{"description":"The draft.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the import."},"organizationId":{"type":"string","format":"uuid","description":"Organization the import belongs to."},"importer":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"The administrator who imports."},"source":{"type":"string","description":"What is imported: `confluence-xml` for the XML space export of Confluence Cloud or Data Center, `confluence-csv` for the CSV space export of Confluence Cloud, `confluence-cloud` and `confluence-dc` to read a space through the Confluence API, `markdown` for a ZIP file of Markdown files, `word` for Word documents (`.docx`). New values can be added in later versions; handle unknown values.","x-extensible-enum":["confluence-xml","confluence-csv","confluence-cloud","confluence-dc","markdown","word"]},"state":{"type":"string","description":"State of the import. `draft` while the wizard is filled in, `analyzing` while the export is read, `ready` when it can be started, `running` while it imports, `held` when the importing administrator lost the permission and another administrator has to take over, `stopping` and `discarding` while the quarantine space is deleted, `review` when the quarantine space waits for a decision, `accepted`, `discarded`, `stopped` and `failed` at the end. A re-import is in `running` while it compares or applies, in `review` while changes wait for a decision, `accepted` when everything is applied, and `superseded` when a newer re-import of the same space replaced it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["draft","analyzing","ready","running","held","stopping","review","accepting","accepted","discarding","discarded","stopped","failed","superseded"]},"draftStep":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Step of the wizard the importer was on, for continuing a draft."},"file":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Where the export comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload","folder"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes, or null when not known yet."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload, or null for a file in the import folder."},"complete":{"type":"boolean","description":"Whether the file is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},{"type":"null"}],"description":"The export file, or null when none is chosen yet."},"spaceName":{"description":"Name of the new space.","type":["string","null"]},"spaceKey":{"description":"Key of the new space.","type":["string","null"]},"archived":{"type":"boolean","description":"Whether the space becomes archived when the import is accepted."},"history":{"type":"boolean","description":"Whether every Confluence version becomes a Lunedo version, or only the current state is imported."},"peopleSource":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"How people are recognized: `token` reads names and e-mail addresses with a read-only Atlassian API token, `list` uses a user list exported from the Atlassian administration, `skip` keeps every author as a placeholder, `source` takes the names Confluence Data Center returns through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["token","list","skip","source"]},"site":{"description":"Confluence site the token is used with, or null.","type":["string","null"]},"email":{"description":"Atlassian e-mail address the token belongs to, or null.","type":["string","null"]},"people":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"People of the export the token could read, or people in the user list; null when unknown."},"withEmail":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Of these, people with a visible e-mail address."}},"required":["kind","site","email","people","withEmail"],"additionalProperties":false},{"type":"null"}],"description":"How people are recognized. The token itself is never returned."},"connection":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","description":"Kind of Confluence the import reads through its API. New values can be added in later versions; handle unknown values.","x-extensible-enum":["cloud","dataCenter"]},"site":{"type":"string","description":"Host name of the Confluence site, with the port when it is not 443."},"basePath":{"type":"string","description":"Context path of Confluence Data Center, such as `/confluence`, or empty."},"email":{"description":"Atlassian e-mail address the API token belongs to, or null.","type":["string","null"]},"account":{"description":"Name of the Confluence account the token belongs to.","type":["string","null"]},"selection":{"type":"array","items":{"type":"object","properties":{"importId":{"type":"string","format":"uuid","description":"ID of the import that reads the space."},"spaceKey":{"type":"string","description":"Key of the Confluence space."}},"required":["importId","spaceKey"],"additionalProperties":false},"description":"Spaces chosen with this connection whose imports are not started yet, one import per space, this import included. Empty once the import has started."}},"required":["kind","site","basePath","email","account","selection"],"additionalProperties":false},{"type":"null"}],"description":"The connection of an import through the Confluence API, or null. Several imports of the same importer can share one connection; the token is never returned."},"files":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","description":"Where the document comes from. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upload"]},"name":{"type":"string","description":"Name of the file."},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size in bytes."},"uploadId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the upload."},"complete":{"type":"boolean","description":"Whether the upload is complete and can be read."}},"required":["kind","name","size","uploadId","complete"],"additionalProperties":false},"description":"The Word documents of a `word` import, in their order. Empty for other imports."},"options":{"type":"object","properties":{"spaceKey":{"description":"Key of the Confluence space read through the API or from a site backup.","type":"string"},"pageIds":{"description":"IDs of the top-level pages whose trees are imported; all pages when left out.","type":"array","items":{"type":"string"}},"blogPosts":{"description":"Whether blog posts are imported; true when left out.","type":"boolean"},"split":{"type":"string","description":"`file` makes each Word document one page, `heading` adds a subpage per top-level heading. New values can be added in later versions; handle unknown values.","x-extensible-enum":["file","heading"]},"knowledgeBase":{"description":"For a `markdown` import: whether the new space is a knowledge base.","type":"boolean"}},"additionalProperties":false,"description":"Options of the source."},"throttledUntil":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Until when Confluence asked Lunedo to slow down, or null. The import continues by itself. ISO 8601 timestamp in UTC."},"waitingFor":{"description":"Key of the Confluence space whose import over the same connection reads or runs first, or null. Imports sharing a connection run one after another; this one continues by itself.","type":["string","null"]},"tokenDeletedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the API token was deleted: when the import was accepted, discarded, stopped or failed, when the importer lost the permission to import, or when the draft was left alone for a week. ISO 8601 timestamp in UTC."},"sourceUrl":{"description":"Address of the Confluence site. Links to pages outside the export point there.","type":["string","null"]},"reviewers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"People who can read the quarantine space and the report."},"phase":{"anyOf":[{"type":"string","x-extensible-enum":["read","compare","space","people","pages","attachments","templates","content","comments","reactions","permissions","baseline","finish","lineage","moves","labels","deletions","done"]},{"type":"null"}],"description":"Step the import is in: `read` reads the export, then `space`, `people`, `pages`, `attachments`, `templates`, `content`, `comments`, `reactions`, `permissions`, `baseline` and `finish`; `done` after the last step. A re-import compares in `compare` and applies in `lineage`, `people`, `pages`, `moves`, `attachments`, `templates`, `content`, `labels`, `comments`, `reactions`, `deletions`, `baseline` and `finish`. New values can be added in later versions; handle unknown values."},"progress":{"type":"object","properties":{"done":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units done in the current step."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Units of the current step, or 0 when not known."}},"required":["done","total"],"additionalProperties":false,"description":"Progress of the current step."},"found":{"anyOf":[{"type":"object","properties":{"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages in the export."},"blogPosts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Blog posts in the export."},"versions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Earlier versions of pages and blog posts."},"comments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Comments, including inline comments and replies."},"likes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Likes on pages, blog posts and comments."},"watchers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Watchers of pages and the space. They are counted, not imported."},"attachments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Attachments of these pages."},"attachmentBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the current attachment versions in bytes."},"people":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"People named in the export."},"macroKinds":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Different macros used on the pages."},"spaceKey":{"type":"string","description":"Key of the space in Confluence."},"spaceName":{"type":"string","description":"Name of the space in Confluence."}},"required":["pages","blogPosts","versions","comments","likes","watchers","attachments","attachmentBytes","people","macroKinds","spaceKey","spaceName"],"additionalProperties":false},{"type":"null"}],"description":"What the export contains, once it was read."},"sourceSpaces":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the space in Confluence."},"name":{"type":"string","description":"Name of the space in Confluence."}},"required":["key","name"],"additionalProperties":false}},{"type":"null"}],"description":"The spaces of a site backup, once it was read; choose one with `options.spaceKey`. Null for exports and backups of one space."},"counts":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"What was imported, by kind: `pages`, `blogPosts`, `versions`, `attachments`, `attachmentVersions`, `comments`, `inlineAnchored`, `inlineMoved`, `likes`, `watchers`, `people`, `peopleMatched`, `restrictions`, `groupsMissing` and `problems`."},"errorCode":{"description":"Why the export could not be read or the import failed, such as `notAnArchive`, `wrongFormat`, `archiveTooLarge`, `unsafeEntryName`, `xmlDeclaration`, `spaceChoiceRequired` (a site backup with several spaces; see `sourceSpaces`) or `internalError`.","type":["string","null"]},"quarantineSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."}},"required":["id","key"],"additionalProperties":false},{"type":"null"}],"description":"The space the import writes into."},"targetSpace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"name":{"type":"string","description":"Name of the space."}},"required":["id","key","name"],"additionalProperties":false},{"type":"null"}],"description":"For a re-import, the space created by the earlier import that the changes go into; otherwise null."},"reimportSpaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space a newer export of the same Confluence space can be imported into again, or null when this import offers no re-import."},"canManage":{"type":"boolean","description":"Whether the caller can change, start, stop, accept or discard the import."},"canResolve":{"type":"boolean","description":"Whether the caller can map people and groups of the import or apply a user list."},"canTakeOver":{"type":"boolean","description":"Whether the caller can take over a held import."},"startedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import finished or failed. ISO 8601 timestamp in UTC."},"decidedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the import was accepted, discarded or stopped. ISO 8601 timestamp in UTC."},"fileExpiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When an uploaded file is deleted. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the import was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the import last changed. ISO 8601 timestamp in UTC."}},"required":["id","organizationId","importer","source","state","draftStep","file","spaceName","spaceKey","archived","history","peopleSource","connection","files","options","throttledUntil","waitingFor","tokenDeletedAt","sourceUrl","reviewers","phase","progress","found","sourceSpaces","counts","errorCode","quarantineSpace","targetSpace","reimportSpaceId","canManage","canResolve","canTakeOver","startedAt","finishedAt","decidedAt","fileExpiresAt","createdAt","updatedAt"],"additionalProperties":false,"description":"An import of a Confluence space."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0001","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0002","importer":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0003","name":"Alex Admin"},"source":"confluence-xml","state":"draft","draftStep":3,"file":{"kind":"upload","name":"export.zip","size":1048576,"uploadId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0004","complete":true},"spaceName":"IT Operations","spaceKey":"ITOPS","archived":false,"sourceUrl":"https://example.atlassian.net/wiki","reviewers":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0005","name":"Robin Reviewer"}],"phase":null,"progress":{"done":0,"total":0},"found":{"pages":120,"blogPosts":6,"versions":340,"comments":85,"likes":30,"watchers":44,"attachments":40,"attachmentBytes":2048000,"people":12,"macroKinds":6,"spaceKey":"ITOPS","spaceName":"IT Operations"},"sourceSpaces":null,"history":false,"peopleSource":{"kind":"token","site":"example.atlassian.net","email":"alex@example.com","people":12,"withEmail":10},"connection":null,"files":[],"options":{},"throttledUntil":null,"waitingFor":null,"tokenDeletedAt":null,"counts":{"pages":120,"blogPosts":6,"attachments":40,"attachmentVersions":52,"comments":85,"people":12,"problems":7},"errorCode":null,"quarantineSpace":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f0006","key":"ITOPS"},"targetSpace":null,"reimportSpaceId":null,"canManage":true,"canResolve":true,"canTakeOver":false,"startedAt":"2026-10-10T08:00:00.000Z","finishedAt":"2026-10-10T08:05:00.000Z","decidedAt":null,"fileExpiresAt":null,"createdAt":"2026-10-10T07:50:00.000Z","updatedAt":"2026-10-10T08:05:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/invitations":{"get":{"operationId":"organizations.invitations","summary":"List invitations","description":"Lists invitations that were neither accepted nor revoked.\n\nRequires the permission `organization.members.manage` on the organization in `organizationId`.","tags":["Members"],"x-lunedo-permission":{"action":"organization.members.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"Pending invitations.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the invitation."},"organizationId":{"type":"string","format":"uuid","description":"ID of the organization."},"email":{"type":"string","description":"Address the invitation was sent to."},"kind":{"type":"string","enum":["member","collaborator","guest"],"description":"Kind of membership the invitation grants."},"role":{"description":"Role given on acceptance, or null.","type":["string","null"]},"membershipExpiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the resulting membership ends, or null. ISO 8601 timestamp in UTC."},"expiresAt":{"type":"string","format":"date-time","description":"When the invitation link stops working. ISO 8601 timestamp in UTC."}},"required":["id","organizationId","email","kind","role","membershipExpiresAt","expiresAt"],"additionalProperties":false,"description":"A pending invitation."},"description":"Invitations, ordered by e-mail address."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"One page of results."},"example":{"items":[{"id":"01929b1f-2c8f-7c73-a490-8b7c6d5eafb0","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","email":"grace@example.org","kind":"member","role":null,"membershipExpiresAt":null,"expiresAt":"2026-10-08T08:00:00.000Z"}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"organizations.invite","summary":"Invite someone","description":"Sends an invitation by e-mail. The link works once and expires.\n\nRequires the permission `organization.members.manage` on the organization in `organizationId`.","tags":["Members"],"x-lunedo-permission":{"action":"organization.members.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","maxLength":254,"format":"email","description":"Address to send the invitation to."},"kind":{"type":"string","enum":["member","collaborator","guest"],"description":"Kind of membership to grant."},"role":{"anyOf":[{"anyOf":[{"type":"object","properties":{"builtIn":{"type":"string","enum":["owner","administrator"],"description":"Key of the built-in role."}},"required":["builtIn"],"additionalProperties":false},{"type":"object","properties":{"customRoleId":{"type":"string","format":"uuid","description":"ID of a custom role of the organization."}},"required":["customRoleId"],"additionalProperties":false,"description":"A custom role."}],"description":"A built-in role."},{"type":"null"}],"description":"The role to give."},"membershipExpiresAt":{"description":"When the resulting membership ends. ISO 8601 timestamp, or null for no expiry. Leave it out to keep the default.","anyOf":[{"description":"When the resulting membership ends. ISO 8601 timestamp; an offset is allowed.","type":"string","format":"date-time"},{"type":"null"}]},"responsibleAccountId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Member responsible for a guest. The caller when left out."}},"required":["email","kind"],"additionalProperties":false,"description":"A new invitation."},"example":{"email":"grace@example.org","kind":"member"}}}},"responses":{"201":{"description":"The new invitation.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the invitation."},"organizationId":{"type":"string","format":"uuid","description":"ID of the organization."},"email":{"type":"string","description":"Address the invitation was sent to."},"kind":{"type":"string","enum":["member","collaborator","guest"],"description":"Kind of membership the invitation grants."},"role":{"description":"Role given on acceptance, or null.","type":["string","null"]},"membershipExpiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the resulting membership ends, or null. ISO 8601 timestamp in UTC."},"expiresAt":{"type":"string","format":"date-time","description":"When the invitation link stops working. ISO 8601 timestamp in UTC."}},"required":["id","organizationId","email","kind","role","membershipExpiresAt","expiresAt"],"additionalProperties":false,"description":"A pending invitation."},"example":{"id":"01929b1f-2c8f-7c73-a490-8b7c6d5eafb0","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","email":"grace@example.org","kind":"member","role":null,"membershipExpiresAt":null,"expiresAt":"2026-10-08T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `expiryInPast`: The expiry lies in the past. `invalidInput`: The request is not valid. `invalidResponsible`: The responsible person is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"expiryInPast":{"value":{"type":"urn:lunedo:problem:expiryInPast","title":"The expiry lies in the past","status":400,"code":"expiryInPast"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidResponsible":{"value":{"type":"urn:lunedo:problem:invalidResponsible","title":"The responsible person is not valid","status":400,"code":"invalidResponsible"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `roleNotFound`: The role does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"roleNotFound":{"value":{"type":"urn:lunedo:problem:roleNotFound","title":"The role does not exist","status":404,"code":"roleNotFound"}}}}}},"409":{"description":"`alreadyMember`: The account is already a member.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"alreadyMember":{"value":{"type":"urn:lunedo:problem:alreadyMember","title":"The account is already a member","status":409,"code":"alreadyMember"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/invitations/{invitationId}":{"delete":{"operationId":"organizations.revoke","summary":"Revoke an invitation","description":"Makes the invitation link stop working.\n\nRequires the permission `organization.members.manage` on the organization in `organizationId`.","tags":["Members"],"x-lunedo-permission":{"action":"organization.members.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"invitationId","in":"path","required":true,"description":"ID of the invitation.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/logo":{"delete":{"operationId":"organizations.removeLogo","summary":"Remove the logo","description":"Removes the logo. Lunedo shows its own logo again.\n\nRequires the permission `organization.update` on the organization in `organizationId`.","tags":["Organizations"],"x-lunedo-permission":{"action":"organization.update","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"put":{"operationId":"organizations.uploadLogo","summary":"Upload a logo","description":"Sets the logo shown on the sign-in page, in the navigation and in e-mails. PNG, JPEG or WebP, at most 256 KiB.\n\nRequires the permission `organization.update` on the organization in `organizationId`.","tags":["Organizations"],"x-lunedo-permission":{"action":"organization.update","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contentType":{"type":"string","enum":["image/png","image/jpeg","image/webp"],"description":"Type of the image."},"data":{"type":"string","maxLength":349528,"format":"base64","contentEncoding":"base64","pattern":"^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$","description":"The image, Base64-encoded."}},"required":["contentType","data"],"additionalProperties":false,"description":"A logo image."},"example":{"contentType":"image/png","data":"iVBORw0KGgo="}}}},"responses":{"200":{"description":"The organization with its new logo reference.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the organization."},"name":{"type":"string","description":"Display name, 1 to 100 characters."},"slug":{"type":"string","description":"Short name used in addresses: lowercase letters, digits and hyphens."},"logoRef":{"description":"Reference to the uploaded logo, or null.","type":["string","null"]},"language":{"type":"string","enum":["en","de"],"description":"Default language of the organization."},"timeZone":{"type":"string","description":"Default IANA time zone, for example `Europe/Vienna`."},"accentColor":{"type":"string","enum":["petrol","blue","violet","amber","red","green","gray"],"description":"Accent color from the palette, from the setting `branding.accentColor`."},"createdAt":{"type":"string","format":"date-time","description":"When the organization was created. ISO 8601 timestamp in UTC."}},"required":["id","name","slug","logoRef","language","timeZone","accentColor","createdAt"],"additionalProperties":false,"description":"An organization."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","name":"Example Inc.","slug":"example-inc","logoRef":"5f2b8c1d9a0e4b7c","language":"en","timeZone":"Europe/Vienna","accentColor":"petrol","createdAt":"2026-10-01T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidLogo`: The logo is not a supported image.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidLogo":{"value":{"type":"urn:lunedo:problem:invalidLogo","title":"The logo is not a supported image","status":400,"code":"invalidLogo"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/members":{"get":{"operationId":"organizations.members","summary":"List members","description":"Lists members, collaborators and guests with their directly assigned roles. The identity provider that manages each account is included only for callers who manage the members of the organization.\n\nRequires the permission `organization.members.view` on the organization in `organizationId`.","tags":["Members"],"x-lunedo-permission":{"action":"organization.members.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}},{"name":"q","in":"query","required":false,"description":"Only items that contain this text, ignoring case: in the name and e-mail address of accounts and members, the name and short name of organizations, and the name and description of groups.","schema":{"type":"string","maxLength":200}}],"responses":{"200":{"description":"Members of the organization.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Display name of the account."},"jobTitle":{"description":"Job title the person entered on their profile, or null.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null without one. Changes whenever the picture changes; load the picture from `GET /api/v1/accounts/{accountId}/picture`.","type":["string","null"]},"email":{"description":"E-mail address, or null for service accounts.","type":["string","null"]},"accountType":{"type":"string","description":"`standard`, `guest`, `portal` or `service`."},"kind":{"type":"string","enum":["member","collaborator","guest"],"description":"Kind of membership in the organization."},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the membership ends, or null. ISO 8601 timestamp in UTC."},"responsibleAccountId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Member responsible for a guest, or null."},"roles":{"type":"array","items":{"type":"object","properties":{"assignmentId":{"type":"string","format":"uuid","description":"ID of the role assignment."},"role":{"type":"string","description":"Name of the role."},"customRoleId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the custom role, or null for a built-in role."},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the assignment ends, or null. ISO 8601 timestamp in UTC."}},"required":["assignmentId","role","customRoleId","expiresAt"],"additionalProperties":false,"description":"A role assigned directly to the account."},"description":"Roles assigned directly to the account in this organization."},"groups":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the group."},"name":{"type":"string","description":"Name of the group."}},"required":["id","name"],"additionalProperties":false,"description":"A group of the organization the account belongs to."},"description":"Groups of this organization the account belongs to, ordered by name."},"twoFactorActive":{"type":"boolean","description":"Whether the account has a confirmed authenticator app or a passkey."},"managedBy":{"description":"The identity provider that manages the account, or null for a local account. Only for callers who manage the members of the organization.","anyOf":[{"type":"object","properties":{"providerId":{"type":"string","format":"uuid","description":"ID of the identity provider."},"providerName":{"type":"string","description":"Name of the identity provider."},"providerType":{"type":"string","description":"Kind of identity provider. New values can be added in later versions; handle unknown values.","x-extensible-enum":["oidc","saml","ldap"]},"source":{"type":"string","enum":["identity","domain"],"description":"Why the provider manages the account: `identity` when an identity of the provider is linked, `domain` when the e-mail domain of the account is assigned to the provider."},"since":{"type":"string","format":"date-time","description":"Since when the provider manages the account. ISO 8601 timestamp in UTC."}},"required":["providerId","providerName","providerType","source","since"],"additionalProperties":false},{"type":"null"}]},"lastActiveAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the account was last active in Lunedo, or null. ISO 8601 timestamp in UTC."}},"required":["accountId","name","jobTitle","pictureRef","email","accountType","kind","expiresAt","responsibleAccountId","roles","groups","twoFactorActive","lastActiveAt"],"additionalProperties":false,"description":"A member of an organization."},"description":"Members, ordered by name."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"One page of results."},"example":{"items":[{"accountId":"01929b1e-8d4b-7e3f-a05c-4d3e2f1a6b7c","name":"Ada Lovelace","jobTitle":"Head of Engineering","pictureRef":"5f2b8c1d9a0e4b7c","email":"ada@example.org","accountType":"standard","kind":"member","expiresAt":null,"responsibleAccountId":null,"roles":[{"assignmentId":"01929b1e-9e5c-7f40-b16d-5e4f3a2b7c8d","role":"administrator","customRoleId":null,"expiresAt":null}],"groups":[{"id":"01929b1e-7a3b-7c2d-8e1f-0a9b8c7d6e5f","name":"Engineering"}],"twoFactorActive":true,"managedBy":null,"lastActiveAt":"2026-10-24T08:15:00.000Z"}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/members/{accountId}":{"delete":{"operationId":"organizations.removeMember","summary":"Remove a member","description":"Removes the account from the organization with its roles and group memberships.\n\nRequires the permission `organization.members.manage` on the organization in `organizationId`.","tags":["Members"],"x-lunedo-permission":{"action":"organization.members.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"accountId","in":"path","required":true,"description":"ID of the member's account.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`homeOrganization`: An account cannot leave its home organization. `lastOwner`: The last owner cannot leave.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"homeOrganization":{"value":{"type":"urn:lunedo:problem:homeOrganization","title":"An account cannot leave its home organization","status":409,"code":"homeOrganization"}},"lastOwner":{"value":{"type":"urn:lunedo:problem:lastOwner","title":"The last owner cannot leave","status":409,"code":"lastOwner"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"get":{"operationId":"organizations.member","summary":"Get a member","description":"Returns a member with how they joined and sign in, their groups with the provider that manages them, and their roles in the spaces of the organization. Spaces are left out unless the caller may view the spaces of the organization; personal and confidential spaces never appear.\n\nRequires the permission `organization.members.manage` on the organization in `organizationId`.","tags":["Members"],"x-lunedo-permission":{"action":"organization.members.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"accountId","in":"path","required":true,"description":"ID of the member's account.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The member.","content":{"application/json":{"schema":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Display name of the account."},"jobTitle":{"description":"Job title the person entered on their profile, or null.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null without one. Changes whenever the picture changes; load the picture from `GET /api/v1/accounts/{accountId}/picture`.","type":["string","null"]},"email":{"description":"E-mail address, or null for service accounts.","type":["string","null"]},"accountType":{"type":"string","description":"`standard`, `guest`, `portal` or `service`."},"kind":{"type":"string","enum":["member","collaborator","guest"],"description":"Kind of membership in the organization."},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the membership ends, or null. ISO 8601 timestamp in UTC."},"responsibleAccountId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Member responsible for a guest, or null."},"roles":{"type":"array","items":{"type":"object","properties":{"assignmentId":{"type":"string","format":"uuid","description":"ID of the role assignment."},"role":{"type":"string","description":"Name of the role."},"customRoleId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the custom role, or null for a built-in role."},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the assignment ends, or null. ISO 8601 timestamp in UTC."}},"required":["assignmentId","role","customRoleId","expiresAt"],"additionalProperties":false,"description":"A role assigned directly to the account."},"description":"Roles assigned directly to the account in this organization."},"groups":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the group."},"name":{"type":"string","description":"Name of the group."}},"required":["id","name"],"additionalProperties":false,"description":"A group of the organization the account belongs to."},"description":"Groups of this organization the account belongs to, ordered by name."},"twoFactorActive":{"type":"boolean","description":"Whether the account has a confirmed authenticator app or a passkey."},"managedBy":{"anyOf":[{"type":"object","properties":{"providerId":{"type":"string","format":"uuid","description":"ID of the identity provider."},"providerName":{"type":"string","description":"Name of the identity provider."},"providerType":{"type":"string","description":"Kind of identity provider. New values can be added in later versions; handle unknown values.","x-extensible-enum":["oidc","saml","ldap"]},"source":{"type":"string","enum":["identity","domain"],"description":"Why the provider manages the account: `identity` when an identity of the provider is linked, `domain` when the e-mail domain of the account is assigned to the provider."},"since":{"type":"string","format":"date-time","description":"Since when the provider manages the account. ISO 8601 timestamp in UTC."}},"required":["providerId","providerName","providerType","source","since"],"additionalProperties":false},{"type":"null"}],"description":"The identity provider that manages the account, or null for a local account. Accounts managed by an OpenID Connect or SAML provider sign in only through it and have no password, passkey or authenticator app in Lunedo; accounts managed by a directory sign in with its password and keep their second factor in Lunedo."},"lastActiveAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the account was last active in Lunedo, or null. ISO 8601 timestamp in UTC."},"joinedAt":{"type":"string","format":"date-time","description":"When the person joined the organization. ISO 8601 timestamp in UTC."},"invitedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who added or invited the person, or null when unknown."},"homeOrganization":{"type":"boolean","description":"Whether this is the home organization of the account."},"twoFactorRequired":{"type":"boolean","description":"Whether the organization requires a second factor."},"signIn":{"type":"object","properties":{"password":{"type":"boolean","description":"Whether the account has a password."},"providers":{"type":"array","items":{"type":"object","properties":{"providerId":{"type":"string","format":"uuid","description":"ID of the identity provider."},"providerName":{"type":"string","description":"Name of the identity provider."}},"required":["providerId","providerName"],"additionalProperties":false,"description":"An identity provider."},"description":"Identity providers linked to the account."}},"required":["password","providers"],"additionalProperties":false,"description":"How the person signs in."},"groupDetails":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the group."},"name":{"type":"string","description":"Name of the group."},"managedBy":{"anyOf":[{"type":"object","properties":{"providerId":{"type":"string","format":"uuid","description":"ID of the identity provider."},"providerName":{"type":"string","description":"Name of the identity provider."}},"required":["providerId","providerName"],"additionalProperties":false,"description":"An identity provider."},{"type":"null"}],"description":"The provider the whole group is synchronized from; its members cannot be changed here."},"viaProvider":{"anyOf":[{"type":"object","properties":{"providerId":{"type":"string","format":"uuid","description":"ID of the identity provider."},"providerName":{"type":"string","description":"Name of the identity provider."}},"required":["providerId","providerName"],"additionalProperties":false,"description":"An identity provider."},{"type":"null"}],"description":"The provider whose mapping rule adds the person to the group; the next synchronization adds them again after a removal."},"spaces":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"How many spaces give the group a role."}},"required":["id","name","managedBy","viaProvider","spaces"],"additionalProperties":false,"description":"A group the person belongs to."},"description":"Groups of this organization the person belongs to, ordered by name."},"spaces":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"name":{"type":"string","description":"Name of the space."},"role":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},"sources":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["direct","group","organizationMembers"],"description":"A role of the person, of a group or of all members."},"groupId":{"type":"string","format":"uuid","description":"The group, for `group`."},"groupName":{"description":"Name of the group, for `group`.","type":"string"}},"required":["kind"],"additionalProperties":false,"description":"Where a role comes from."},"description":"Where the roles come from; the highest is shown as `role`."}},"required":["id","key","name","role","sources"],"additionalProperties":false,"description":"A space the person has a role in."}},{"type":"null"}],"description":"Spaces of the organization the person has a role in, without personal and confidential spaces. Null when the caller may not view the spaces of the organization."}},"required":["accountId","name","jobTitle","pictureRef","email","accountType","kind","expiresAt","responsibleAccountId","roles","groups","twoFactorActive","managedBy","lastActiveAt","joinedAt","invitedBy","homeOrganization","twoFactorRequired","signIn","groupDetails","spaces"],"additionalProperties":false,"description":"A member of an organization with groups, spaces and sign-in."},"example":{"accountId":"01929b1e-8d4b-7e3f-a05c-4d3e2f1a6b7c","name":"Ada Lovelace","jobTitle":"Head of Engineering","pictureRef":"5f2b8c1d9a0e4b7c","email":"ada@example.org","accountType":"standard","kind":"member","expiresAt":null,"responsibleAccountId":null,"roles":[{"assignmentId":"01929b1e-9e5c-7f40-b16d-5e4f3a2b7c8d","role":"administrator","customRoleId":null,"expiresAt":null}],"groups":[{"id":"01929b1e-7a3b-7c2d-8e1f-0a9b8c7d6e5f","name":"Engineering"}],"twoFactorActive":true,"managedBy":null,"lastActiveAt":"2026-10-24T08:15:00.000Z","joinedAt":"2026-08-21T09:58:00.000Z","invitedBy":{"id":"01929b1e-8d4b-7e3f-a05c-4d3e2f1a6b70","name":"Olivia Owner"},"homeOrganization":true,"twoFactorRequired":false,"signIn":{"password":true,"providers":[]},"groupDetails":[{"id":"01929b1e-7a3b-7c2d-8e1f-0a9b8c7d6e5f","name":"Engineering","managedBy":null,"viaProvider":null,"spaces":2}],"spaces":[{"id":"01929b1e-7a3b-7c2d-8e1f-0a9b8c7d6e60","key":"ITOPS","name":"IT Operations","role":"editor","sources":[{"kind":"group","groupId":"01929b1e-7a3b-7c2d-8e1f-0a9b8c7d6e5f","groupName":"Engineering"}]}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"patch":{"operationId":"organizations.updateMember","summary":"Change a membership","description":"Changes when a membership ends or who is responsible for a guest.\n\nRequires the permission `organization.members.manage` on the organization in `organizationId`.","tags":["Members"],"x-lunedo-permission":{"action":"organization.members.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"accountId","in":"path","required":true,"description":"ID of the member's account.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"expiresAt":{"description":"When the membership ends. ISO 8601 timestamp, or null for no expiry. Leave it out to keep the default.","anyOf":[{"description":"When the membership ends. ISO 8601 timestamp; an offset is allowed.","type":"string","format":"date-time"},{"type":"null"}]},"responsibleAccountId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Member responsible for a guest, or null."}},"additionalProperties":false,"description":"Fields to change."},"example":{"expiresAt":"2026-12-31T23:59:59Z"}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `expiryInPast`: The expiry lies in the past. `invalidInput`: The request is not valid. `invalidResponsible`: The responsible person is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"expiryInPast":{"value":{"type":"urn:lunedo:problem:expiryInPast","title":"The expiry lies in the past","status":400,"code":"expiryInPast"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidResponsible":{"value":{"type":"urn:lunedo:problem:invalidResponsible","title":"The responsible person is not valid","status":400,"code":"invalidResponsible"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/members/{accountId}/permissions":{"get":{"operationId":"organizations.permissions","summary":"Explain a member's permissions","description":"Shows for every organization action whether the member may perform it, and why.\n\nRequires the permission `organization.members.manage` on the organization in `organizationId`.","tags":["Members"],"x-lunedo-permission":{"action":"organization.members.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"accountId","in":"path","required":true,"description":"ID of the member's account.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"One decision per action.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"action":{"type":"string","description":"Name of the action."},"allowed":{"type":"boolean","description":"Whether the account may perform the action."},"grants":{"type":"array","items":{"description":"Role, membership or rule that allows it.","$ref":"#/components/schemas/Schema113ae44d8375"},"description":"Why it is allowed."},"denials":{"type":"array","items":{"type":"string","description":"Reason code."},"description":"Why it is not allowed."}},"required":["action","allowed","grants","denials"],"additionalProperties":false,"description":"Authorization decision for one action."},"description":"Decisions, one per organization action."},"example":[{"action":"organization.spaces.manage","allowed":true,"grants":[{"kind":"role","role":{"customRoleId":"01929b1f-1b7e-7b62-938f-7a6b5c4d9eaf"},"via":{"type":"account"},"expiresAt":null}],"denials":[]}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/members/{accountId}/spaces":{"post":{"operationId":"organizations.addToSpaces","summary":"Add a member to spaces","description":"Gives the member a role in each of the spaces, all or none. For each space the caller must be its space admin or manage the spaces of the organization. Personal and confidential spaces are refused. When an organization administrator adds someone to a space they do not administer, its space admins are notified and the audit log records it; only space admins give the role `admin`. Only active members of the organization can be added, and nobody adds themselves.\n\nRequires the permission `organization.view` on the organization in `organizationId`.","tags":["Members"],"x-lunedo-permission":{"action":"organization.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"accountId","in":"path","required":true,"description":"ID of the member's account.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"spaces":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"The space."},"role":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."}},"required":["spaceId","role"],"additionalProperties":false,"description":"A space and the role the person gets there."},"description":"1 to 50 different spaces."}},"required":["spaces"],"additionalProperties":false,"description":"Spaces to add a person to."},"example":{"spaces":[{"spaceId":"01929b1e-7a3b-7c2d-8e1f-0a9b8c7d6e60","role":"reader"}]}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid. `invalidSpaces`: Choose between 1 and 50 different spaces.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidSpaces":{"value":{"type":"urn:lunedo:problem:invalidSpaces","title":"Choose between 1 and 50 different spaces","status":400,"code":"invalidSpaces"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`administratorBySpaceAdmins`: Only space admins appoint space admins. `csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `selfExtension`: Nobody can extend their own permissions.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"administratorBySpaceAdmins":{"value":{"type":"urn:lunedo:problem:administratorBySpaceAdmins","title":"Only space admins appoint space admins","status":403,"code":"administratorBySpaceAdmins"}},"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"selfExtension":{"value":{"type":"urn:lunedo:problem:selfExtension","title":"Nobody can extend their own permissions","status":403,"code":"selfExtension"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`alreadyGranted`: The holder already has a role in the space.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"alreadyGranted":{"value":{"type":"urn:lunedo:problem:alreadyGranted","title":"The holder already has a role in the space","status":409,"code":"alreadyGranted"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/members/{accountId}/spaces/{spaceId}":{"delete":{"operationId":"organizations.removeFromSpace","summary":"Remove a member's own role in a space","description":"Removes the role the member holds in the space of their own; roles through groups or all members stay. The caller must be space admin of the space or manage the spaces of the organization. When an organization administrator removes someone from a space they do not administer, its space admins are notified and the audit log records it. Space admins are never removed this way.\n\nRequires the permission `organization.view` on the organization in `organizationId`.","tags":["Members"],"x-lunedo-permission":{"action":"organization.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"accountId","in":"path","required":true,"description":"ID of the member's account.","schema":{"type":"string","format":"uuid"}},{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The removed role, to add it again for undo.","content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"ID of the space."},"role":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"The role the member held of their own."}},"required":["spaceId","role"],"additionalProperties":false,"description":"The role that was removed."},"example":{"spaceId":"01929b1e-7a3b-7c2d-8e1f-0a9b8c7d6e60","role":"editor"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `permissionNotFound`: The permission does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"permissionNotFound":{"value":{"type":"urn:lunedo:problem:permissionNotFound","title":"The permission does not exist","status":404,"code":"permissionNotFound"}}}}}},"409":{"description":"`administratorKept`: Space admins are removed in the permissions of the space.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"administratorKept":{"value":{"type":"urn:lunedo:problem:administratorKept","title":"Space admins are removed in the permissions of the space","status":409,"code":"administratorKept"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/people/{accountId}/access":{"get":{"operationId":"accessRequests.person","summary":"What can a person do?","description":"Lists all access of a person in the organization with the reason for each entry: role in a space, group, share or link. Entries that are stored but have no effect because the person's membership ended are marked inactive. Shared pages the caller cannot read are only counted per space; confidential spaces the caller does not belong to are only counted.\n\nRequires the permission `organization.access.view` on the organization in `organizationId`.","tags":["Access"],"x-lunedo-permission":{"action":"organization.access.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"accountId","in":"path","required":true,"description":"The person.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The access of the person.","content":{"application/json":{"schema":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"The person."},"name":{"description":"Name, or null when hidden.","type":["string","null"]},"email":{"description":"E-mail address, when the caller may see it.","type":["string","null"]},"entries":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","description":"`restrictedPages` counts shared pages the caller cannot read, without titles. New values can be added in later versions; handle unknown values.","x-extensible-enum":["space","share","link","restrictedPages"]},"spaceId":{"type":"string","format":"uuid","description":"The space."},"spaceName":{"type":"string","description":"Name of the space."},"spaceKey":{"type":"string","description":"Key of the space."},"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The page, for shares and links."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the page in the addresses of the app."},{"type":"null"}],"description":"Number of the page in the addresses of the app, for shares and links."},"itemTitle":{"description":"Title of the page.","type":["string","null"]},"role":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"]},{"type":"null"}],"description":"What the person may do."},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of pages for `restrictedPages`; otherwise 1, or 2 for a share with the pages below."},"reasons":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"Kind of reason. New values can be added in later versions; handle unknown values.","x-extensible-enum":["spaceRole","share","link"]},"role":{"description":"Role that the reason grants.","type":"string","enum":["reader","commenter","editor","admin"]},"via":{"type":"object","properties":{"type":{"type":"string","description":"How the role is held. New values can be added in later versions; handle unknown values.","x-extensible-enum":["account","group","organizationMembers","instanceUsers","visibility"]},"groupId":{"type":"string","format":"uuid","description":"The group."},"name":{"description":"Name of the group.","type":"string"},"visibility":{"description":"Visibility of the space that grants the role.","type":"string"}},"required":["type"],"additionalProperties":false,"description":"How a role in the space is held."},"itemId":{"type":"string","format":"uuid","description":"Page that was shared."},"itemTitle":{"description":"Its title, or null when the caller cannot see it.","type":["string","null"]},"inherited":{"description":"Whether the share comes from a page above.","type":"boolean"},"linkId":{"type":"string","format":"uuid","description":"The share link."},"scope":{"description":"Scope of the share link.","type":"string"},"inactive":{"type":"string","description":"Set when the entry is stored but grants nothing: `membershipEnded` means the person is no longer a member of the organization the space belongs to. It applies again if they become a member again. New values can be added in later versions; handle unknown values.","x-extensible-enum":["membershipEnded"]}},"required":["type"],"additionalProperties":false,"description":"Why a person has access, or an entry that has no effect."},"description":"Why."},"inactive":{"anyOf":[{"type":"string","x-extensible-enum":["membershipEnded"]},{"type":"null"}],"description":"Set when the entry grants nothing; `role` is then the role it would grant. New values can be added in later versions; handle unknown values."}},"required":["kind","spaceId","spaceName","spaceKey","itemId","number","itemTitle","role","count","reasons","inactive"],"additionalProperties":false,"description":"An access of the person."},"description":"All access of the person in the organization."},"confidentialSpaceCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of confidential spaces the person belongs to and the caller does not. They are not listed in `entries`, and their names and keys stay hidden."}},"required":["accountId","name","email","entries","confidentialSpaceCount"],"additionalProperties":false,"description":"What a person can do."},"example":{"accountId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a22","name":"Lukas Hofer","email":"lukas.hofer@example.org","entries":[{"kind":"space","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a00","spaceName":"IT Operations","spaceKey":"ITOPS","itemId":null,"number":null,"itemTitle":null,"role":"reader","count":1,"reasons":[{"type":"spaceRole","role":"reader","via":{"type":"group","groupId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a30","name":"IT Operations"}}],"inactive":null}],"confidentialSpaceCount":0}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `personNotFound`: The person does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"personNotFound":{"value":{"type":"urn:lunedo:problem:personNotFound","title":"The person does not exist","status":404,"code":"personNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/personal-spaces":{"get":{"operationId":"personalSpaces.forOrganization","summary":"List personal spaces of deactivated people","description":"Lists the personal spaces whose owner has this organization as home organization, is deactivated and has left other active members behind. Shows key, size and last change, never names or content.\n\nRequires the permission `organization.spaces.view` on the organization in `organizationId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"organization.spaces.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"Personal spaces, ordered by key.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"createdAt":{"type":"string","format":"date-time","description":"When the space was created. ISO 8601 timestamp in UTC."},"members":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people and groups with a role."},"activeMembers":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of active members besides the owner."},"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of pages, without the trash."},"lastChangedAt":{"type":"string","format":"date-time","description":"Last change of the space or its content. ISO 8601 timestamp in UTC."},"needsAdministrator":{"type":"boolean","description":"True when no active space admin remains but other members do; one of them can be appointed."}},"required":["id","key","createdAt","members","activeMembers","pages","lastChangedAt","needsAdministrator"],"additionalProperties":false,"description":"A personal space of a deactivated person as organization administrators see it."},"description":"Personal spaces."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"One page of results."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5b01","key":"P7K2M9QX","createdAt":"2026-09-01T08:00:00.000Z","members":3,"activeMembers":2,"pages":12,"lastChangedAt":"2026-10-08T15:00:00.000Z","needsAdministrator":true}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/personal-spaces/{spaceId}/administrator":{"post":{"operationId":"personalSpaces.appoint","summary":"Appoint a space admin of a personal space","description":"Makes a remaining member space admin of a personal space whose owner is deactivated and that has no active space admin. Never the caller and never someone who is not a member. The appointment is audited and the member is notified.\n\nRequires the permission `organization.spaces.manage` on the organization in `organizationId`. Needs a signed-in session; API tokens are refused.","tags":["Spaces"],"x-lunedo-permission":{"action":"organization.spaces.manage","resource":"organization","parameter":"organizationId"},"security":[{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"spaceId","in":"path","required":true,"description":"ID of the personal space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"Remaining member who becomes space admin."}},"required":["accountId"],"additionalProperties":false,"description":"The new space admin."},"example":{"accountId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a21"}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid. `selfAppointment`: Nobody can give themselves access this way.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"selfAppointment":{"value":{"type":"urn:lunedo:problem:selfAppointment","title":"Nobody can give themselves access this way","status":400,"code":"selfAppointment"}}}}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `reauthenticationRequired`: Confirm your identity first. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"reauthenticationRequired":{"value":{"type":"urn:lunedo:problem:reauthenticationRequired","title":"Confirm your identity first","status":403,"code":"reauthenticationRequired"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`spaceHasAdministrator`: The space has a space admin.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"spaceHasAdministrator":{"value":{"type":"urn:lunedo:problem:spaceHasAdministrator","title":"The space has a space admin","status":409,"code":"spaceHasAdministrator"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/personal-spaces/{spaceId}/remaining-members":{"get":{"operationId":"personalSpaces.remaining","summary":"List the remaining members of a personal space without space admin","description":"Lists the names of the active members of a personal space whose owner is deactivated, without the caller. The list is empty while the space has an active space admin.\n\nRequires the permission `organization.spaces.manage` on the organization in `organizationId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"organization.spaces.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"spaceId","in":"path","required":true,"description":"ID of the personal space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The remaining members.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false,"description":"A member."},"description":"Remaining members."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a21","name":"Anna Berger"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/role-assignments":{"get":{"operationId":"organizations.assignments","summary":"List role assignments","description":"Lists who holds which role in the organization.\n\nRequires the permission `organization.roles.view` on the organization in `organizationId`.","tags":["Roles"],"x-lunedo-permission":{"action":"organization.roles.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"Role assignments of the organization.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the assignment."},"scope":{"type":"string","enum":["instance","organization"],"description":"Level of the assignment."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the organization, or null for instance assignments."},"role":{"type":"string","description":"Name of the role."},"builtInRole":{"anyOf":[{"type":"string","enum":["owner","administrator","member","securityAuditor"]},{"type":"null"}],"description":"Key of the built-in role, or null for a custom role."},"customRoleId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the custom role, or null for a built-in role."},"principalKind":{"type":"string","enum":["account","group","organizationMembers","instanceUsers"],"description":"Who receives the role."},"principalId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the account or group, or null for all members or all users."},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the assignment ends, or null. ISO 8601 timestamp in UTC."}},"required":["id","scope","organizationId","role","builtInRole","customRoleId","principalKind","principalId","expiresAt"],"additionalProperties":false,"description":"A role given to a principal."},"description":"Assignments, ordered by ID."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"One page of results."},"example":{"items":[{"id":"01929b1e-9e5c-7f40-b16d-5e4f3a2b7c8d","scope":"organization","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","role":"Handbook editors","builtInRole":null,"customRoleId":"01929b1f-1b7e-7b62-938f-7a6b5c4d9eaf","principalKind":"group","principalId":"01929b1f-0a6d-7a51-827e-6f5a4b3c8d9e","expiresAt":null}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"organizations.assign","summary":"Assign a role","description":"Gives a role to an account or a group. Roles go to individual accounts and groups only.\n\nRequires the permission `organization.roles.manage` on the organization in `organizationId`.","tags":["Roles"],"x-lunedo-permission":{"action":"organization.roles.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"role":{"anyOf":[{"type":"object","properties":{"builtIn":{"type":"string","enum":["owner","administrator"],"description":"Key of the built-in role."}},"required":["builtIn"],"additionalProperties":false,"description":"A built-in role."},{"type":"object","properties":{"customRoleId":{"type":"string","format":"uuid","description":"ID of a custom role of the organization."}},"required":["customRoleId"],"additionalProperties":false,"description":"A custom role."}],"description":"The role to give."},"principal":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"account","description":"One account."},"id":{"type":"string","format":"uuid","description":"ID of the account."}},"required":["kind","id"],"additionalProperties":false,"description":"An account, including service accounts."},{"type":"object","properties":{"kind":{"type":"string","const":"group","description":"All members of a group."},"id":{"type":"string","format":"uuid","description":"ID of the group."}},"required":["kind","id"],"additionalProperties":false,"description":"A group."},{"type":"object","properties":{"kind":{"type":"string","const":"organizationMembers","description":"Every member of the organization."}},"required":["kind"],"additionalProperties":false,"description":"All members."},{"type":"object","properties":{"kind":{"type":"string","const":"instanceUsers","description":"Every internal user of the instance who is a member."}},"required":["kind"],"additionalProperties":false,"description":"All internal users."}],"description":"Who receives the role. All members and all internal users are refused with `roleNeedsAccountOrGroup`: roles go to individual accounts and groups only."},"expiresAt":{"description":"When the assignment ends. ISO 8601 timestamp, or null for no expiry. Leave it out to keep the default.","anyOf":[{"description":"When the assignment ends. ISO 8601 timestamp; an offset is allowed.","type":"string","format":"date-time"},{"type":"null"}]}},"required":["role","principal"],"additionalProperties":false,"description":"A role assignment. Nobody can give more than they hold themselves."},"example":{"role":{"customRoleId":"01929b1f-1b7e-7b62-938f-7a6b5c4d9eaf"},"principal":{"kind":"group","id":"01929b1f-0a6d-7a51-827e-6f5a4b3c8d9e"}}}}},"responses":{"201":{"description":"The new assignment.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the assignment."},"scope":{"type":"string","enum":["instance","organization"],"description":"Level of the assignment."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the organization, or null for instance assignments."},"role":{"type":"string","description":"Name of the role."},"builtInRole":{"anyOf":[{"type":"string","enum":["owner","administrator","member","securityAuditor"]},{"type":"null"}],"description":"Key of the built-in role, or null for a custom role."},"customRoleId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the custom role, or null for a built-in role."},"principalKind":{"type":"string","enum":["account","group","organizationMembers","instanceUsers"],"description":"Who receives the role."},"principalId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the account or group, or null for all members or all users."},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the assignment ends, or null. ISO 8601 timestamp in UTC."}},"required":["id","scope","organizationId","role","builtInRole","customRoleId","principalKind","principalId","expiresAt"],"additionalProperties":false,"description":"A role given to a principal."},"example":{"id":"01929b1e-9e5c-7f40-b16d-5e4f3a2b7c8d","scope":"organization","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","role":"Handbook editors","builtInRole":null,"customRoleId":"01929b1f-1b7e-7b62-938f-7a6b5c4d9eaf","principalKind":"group","principalId":"01929b1f-0a6d-7a51-827e-6f5a4b3c8d9e","expiresAt":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `expiryInPast`: The expiry lies in the past. `invalidInput`: The request is not valid. `invalidPrincipal`: The role cannot go to this principal. `ownerExpiry`: The owner role cannot expire. `roleNeedsAccountOrGroup`: The role can only go to individual accounts and groups. `roleNotAssignable`: The role cannot be assigned.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"expiryInPast":{"value":{"type":"urn:lunedo:problem:expiryInPast","title":"The expiry lies in the past","status":400,"code":"expiryInPast"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidPrincipal":{"value":{"type":"urn:lunedo:problem:invalidPrincipal","title":"The role cannot go to this principal","status":400,"code":"invalidPrincipal"}},"ownerExpiry":{"value":{"type":"urn:lunedo:problem:ownerExpiry","title":"The owner role cannot expire","status":400,"code":"ownerExpiry"}},"roleNeedsAccountOrGroup":{"value":{"type":"urn:lunedo:problem:roleNeedsAccountOrGroup","title":"The role can only go to individual accounts and groups","status":400,"code":"roleNeedsAccountOrGroup"}},"roleNotAssignable":{"value":{"type":"urn:lunedo:problem:roleNotAssignable","title":"The role cannot be assigned","status":400,"code":"roleNotAssignable"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `roleNotFound`: The role does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"roleNotFound":{"value":{"type":"urn:lunedo:problem:roleNotFound","title":"The role does not exist","status":404,"code":"roleNotFound"}}}}}},"409":{"description":"`alreadyAssigned`: The role is already assigned.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"alreadyAssigned":{"value":{"type":"urn:lunedo:problem:alreadyAssigned","title":"The role is already assigned","status":409,"code":"alreadyAssigned"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/role-assignments/{assignmentId}":{"delete":{"operationId":"organizations.unassign","summary":"Remove a role assignment","description":"Takes a role away. The permissions end at once.\n\nRequires the permission `organization.roles.manage` on the organization in `organizationId`.","tags":["Roles"],"x-lunedo-permission":{"action":"organization.roles.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"assignmentId","in":"path","required":true,"description":"ID of the role assignment.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`lastOwner`: The last owner cannot leave.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"lastOwner":{"value":{"type":"urn:lunedo:problem:lastOwner","title":"The last owner cannot leave","status":409,"code":"lastOwner"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/roles":{"get":{"operationId":"organizations.roles","summary":"List custom roles","description":"Lists the roles defined in the organization. Built-in roles are not listed.\n\nRequires the permission `organization.roles.view` on the organization in `organizationId`.","tags":["Roles"],"x-lunedo-permission":{"action":"organization.roles.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"Custom roles of the organization.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the role."},"scope":{"type":"string","enum":["instance","organization"],"description":"Level the role applies to."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the organization, or null for instance roles."},"name":{"type":"string","description":"Name of the role, 1 to 100 characters."},"areas":{"type":"object","propertyNames":{"type":"string","description":"Area name."},"additionalProperties":{"type":"string","enum":["view","manage"],"description":"`view` reads, `manage` also changes."},"description":"Access level per area. Areas that are left out grant nothing."}},"required":["id","scope","organizationId","name","areas"],"additionalProperties":false,"description":"A role defined by an administrator."},"description":"Roles, ordered by name."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"One page of results."},"example":{"items":[{"id":"01929b1f-1b7e-7b62-938f-7a6b5c4d9eaf","scope":"organization","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","name":"Handbook editors","areas":{"spaces":"manage","membersAndGroups":"view"}}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"organizations.createRole","summary":"Create a custom role","description":"Defines a role from areas and access levels.\n\nRequires the permission `organization.roles.manage` on the organization in `organizationId`.","tags":["Roles"],"x-lunedo-permission":{"action":"organization.roles.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Name of the role, 1 to 100 characters, unique in the organization."},"areas":{"type":"object","properties":{"membersAndGroups":{"description":"Access to the organization area `membersAndGroups`.","type":"string","enum":["view","manage"]},"spaces":{"description":"Access to the organization area `spaces`.","type":"string","enum":["view","manage"]},"settings":{"description":"Access to the organization area `settings`.","type":"string","enum":["view","manage"]},"signInAndSecurity":{"description":"Access to the organization area `signInAndSecurity`.","type":"string","enum":["view","manage"]},"integrationsAndApi":{"description":"Access to the organization area `integrationsAndApi`.","type":"string","enum":["view","manage"]},"auditLog":{"description":"Access to the organization area `auditLog`.","type":"string","enum":["view","manage"]}},"additionalProperties":false,"description":"Access level per organization area. Areas that are left out grant nothing."}},"required":["name","areas"],"additionalProperties":false,"description":"A new custom role. Nobody can define a role with more than they hold themselves."},"example":{"name":"Handbook editors","areas":{"spaces":"manage"}}}}},"responses":{"201":{"description":"The new role.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the role."},"scope":{"type":"string","enum":["instance","organization"],"description":"Level the role applies to."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the organization, or null for instance roles."},"name":{"type":"string","description":"Name of the role, 1 to 100 characters."},"areas":{"type":"object","propertyNames":{"type":"string","description":"Area name."},"additionalProperties":{"type":"string","enum":["view","manage"],"description":"`view` reads, `manage` also changes."},"description":"Access level per area. Areas that are left out grant nothing."}},"required":["id","scope","organizationId","name","areas"],"additionalProperties":false,"description":"A role defined by an administrator."},"example":{"id":"01929b1f-1b7e-7b62-938f-7a6b5c4d9eaf","scope":"organization","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","name":"Handbook editors","areas":{"spaces":"manage","membersAndGroups":"view"}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`roleNameTaken`: The role name is taken.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"roleNameTaken":{"value":{"type":"urn:lunedo:problem:roleNameTaken","title":"The role name is taken","status":409,"code":"roleNameTaken"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/roles/{roleId}":{"delete":{"operationId":"organizations.deleteRole","summary":"Delete a custom role","description":"Deletes the role and all its assignments.\n\nRequires the permission `organization.roles.manage` on the organization in `organizationId`.","tags":["Roles"],"x-lunedo-permission":{"action":"organization.roles.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"roleId","in":"path","required":true,"description":"ID of the custom role.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `roleNotFound`: The role does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"roleNotFound":{"value":{"type":"urn:lunedo:problem:roleNotFound","title":"The role does not exist","status":404,"code":"roleNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"patch":{"operationId":"organizations.updateRole","summary":"Change a custom role","description":"Renames a role or changes its areas. Holders get the new permissions at once.\n\nRequires the permission `organization.roles.manage` on the organization in `organizationId`.","tags":["Roles"],"x-lunedo-permission":{"action":"organization.roles.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"roleId","in":"path","required":true,"description":"ID of the custom role.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"New name of the role.","type":"string","minLength":1,"maxLength":100},"areas":{"description":"New access levels. Replaces all areas.","type":"object","properties":{"membersAndGroups":{"description":"Access to the organization area `membersAndGroups`.","type":"string","enum":["view","manage"]},"spaces":{"description":"Access to the organization area `spaces`.","type":"string","enum":["view","manage"]},"settings":{"description":"Access to the organization area `settings`.","type":"string","enum":["view","manage"]},"signInAndSecurity":{"description":"Access to the organization area `signInAndSecurity`.","type":"string","enum":["view","manage"]},"integrationsAndApi":{"description":"Access to the organization area `integrationsAndApi`.","type":"string","enum":["view","manage"]},"auditLog":{"description":"Access to the organization area `auditLog`.","type":"string","enum":["view","manage"]}},"additionalProperties":false}},"additionalProperties":false,"description":"Fields to change."},"example":{"areas":{"spaces":"view"}}}}},"responses":{"200":{"description":"The changed role.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the role."},"scope":{"type":"string","enum":["instance","organization"],"description":"Level the role applies to."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the organization, or null for instance roles."},"name":{"type":"string","description":"Name of the role, 1 to 100 characters."},"areas":{"type":"object","propertyNames":{"type":"string","description":"Area name."},"additionalProperties":{"type":"string","enum":["view","manage"],"description":"`view` reads, `manage` also changes."},"description":"Access level per area. Areas that are left out grant nothing."}},"required":["id","scope","organizationId","name","areas"],"additionalProperties":false,"description":"A role defined by an administrator."},"example":{"id":"01929b1f-1b7e-7b62-938f-7a6b5c4d9eaf","scope":"organization","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","name":"Handbook editors","areas":{"spaces":"manage","membersAndGroups":"view"}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `roleNotFound`: The role does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"roleNotFound":{"value":{"type":"urn:lunedo:problem:roleNotFound","title":"The role does not exist","status":404,"code":"roleNotFound"}}}}}},"409":{"description":"`roleNameTaken`: The role name is taken.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"roleNameTaken":{"value":{"type":"urn:lunedo:problem:roleNameTaken","title":"The role name is taken","status":409,"code":"roleNameTaken"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/search":{"get":{"operationId":"search.search","summary":"Search the content of an organization","description":"Searches pages, blog posts, comments, attachments, running topics and decisions of all spaces of the organization the caller can read, for the search page and for search while typing. The text of PDF, Word and Excel attachments is searched, file names of all attachments. Results, counts and excerpts only ever include content the caller can read; pages shared with the caller show no space or path. Drafts, attachments added only in a draft and private meeting notes are never searched. Unknown filter values and values of things the caller cannot see give the same empty answer.\n\nRequires the permission `organization.search` on the organization in `organizationId`.","tags":["Search"],"x-lunedo-permission":{"action":"organization.search","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"q","in":"query","required":false,"description":"The search text. Words must all match. `\"exact phrase\"` matches the words in this order, `-word` excludes a word, `OR` between two words matches either. The operators `space:KEY`, `label:name`, `author:name`, `status:name` (default values also by their English name, such as `status:verified`) and `type:page|blog|comment|attachment|topic|decision` filter like the parameters; quote values with spaces.","schema":{"default":"","type":"string","maxLength":500}},{"name":"mode","in":"query","required":false,"description":"`full` (default) for the search page with counts per filter value and pages of results. `quick` for search while typing: few results, the last word also matches longer words, results of `spaceId` first, no counts and no further pages.","schema":{"default":"full","type":"string","enum":["full","quick"]}},{"name":"spaceId","in":"query","required":false,"description":"In quick search, the space the person is in; its results come first.","schema":{"type":"string","format":"uuid"}},{"name":"spaceIds","in":"query","required":false,"description":"Only results in these spaces. Up to 20 values, separated by commas.","schema":{"type":"string","maxLength":2000}},{"name":"types","in":"query","required":false,"description":"Only results of these types: `page`, `blogPost`, `comment`, `attachment`, `topic` or `decision`. Up to 20 values, separated by commas.","schema":{"type":"string","maxLength":2000}},{"name":"labels","in":"query","required":false,"description":"Only pages with at least one of these labels. Up to 20 values, separated by commas.","schema":{"type":"string","maxLength":2000}},{"name":"authorIds","in":"query","required":false,"description":"Only results by these authors. Up to 20 values, separated by commas.","schema":{"type":"string","maxLength":2000}},{"name":"statusIds","in":"query","required":false,"description":"Only pages with one of these status values. Up to 20 values, separated by commas.","schema":{"type":"string","maxLength":2000}},{"name":"languages","in":"query","required":false,"description":"Only results in one of these content languages. Up to 20 values, separated by commas.","schema":{"type":"string","maxLength":2000}},{"name":"includeArchived","in":"query","required":false,"description":"`true` includes archived pages. Default `false`.","schema":{"default":"false","type":"string","enum":["true","false"]}},{"name":"updatedAfter","in":"query","required":false,"description":"Only results changed at or after this time. ISO 8601 timestamp; an offset is allowed.","schema":{"type":"string","format":"date-time"}},{"name":"updatedBefore","in":"query","required":false,"description":"Only results changed before this time. ISO 8601 timestamp; an offset is allowed.","schema":{"type":"string","format":"date-time"}},{"name":"sort","in":"query","required":false,"description":"`relevance` (default), best matches first, or `newest`, last changed first.","schema":{"default":"relevance","type":"string","enum":["relevance","newest"]}},{"name":"cursor","in":"query","required":false,"description":"Cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":500}},{"name":"limit","in":"query","required":false,"description":"Maximum number of results, from 1 to 50. Default 20, in quick search 8.","schema":{"type":"integer","minimum":1,"maximum":50}}],"responses":{"200":{"description":"The results.","content":{"application/json":{"schema":{"type":"object","properties":{"results":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"`page`, `blogPost`, `comment`, `attachment`, `topic` (a running topic, its updates or a comment on it) or `decision`. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","blogPost","whiteboard","comment","attachment","topic","decision"]},"id":{"type":"string","format":"uuid","description":"ID of the page, blog post, comment, attachment, running topic or decision; for a comment on a running topic, of the comment."},"itemId":{"type":"string","format":"uuid","description":"ID of the page, blog post or running topic the result belongs to; for a decision, the meeting it was recorded in."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item `itemId` names, in the addresses of the app."},"itemType":{"type":"string","description":"What `itemId` is: `page`, `blogPost` or `topic` (a running topic), so that clients open the right screen. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","blogPost","topic","whiteboard"]},"title":{"type":"string","description":"Title of the page, blog post or running topic; for a comment or attachment, of its page; for a decision, of its meeting."},"heading":{"type":"string","description":"Heading of the section that matched, the file name of an attachment, the meeting of a topic update, or an empty string."},"anchor":{"description":"Anchor of that heading on the page, or null.","type":["string","null"]},"excerpt":{"type":"array","items":{"type":"object","properties":{"text":{"type":"string","description":"Part of the excerpt."},"highlighted":{"type":"boolean","description":"Whether this part matched the search words."}},"required":["text","highlighted"],"additionalProperties":false,"description":"Part of an excerpt."},"description":"Text around the matched words, from content the caller can read only."},"space":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"name":{"type":"string","description":"Name of the space. Empty for personal spaces, which clients name themselves."},"displayName":{"type":"string","description":"Name to show: the name of the space, or for a personal space without a name of its own \"Personal space of\" and the owner's name, in the owner's language."},"personal":{"type":"boolean","description":"Whether this is a personal space."},"knowledgeBase":{"type":"boolean","description":"Whether the space is a knowledge base, whose pages are articles."},"mine":{"type":"boolean","description":"Whether it is the caller's own personal space."}},"required":["id","key","name","displayName","personal","knowledgeBase","mine"],"additionalProperties":false,"description":"A space the caller can open."},{"type":"null"}],"description":"The space, or null when the caller can read the page only because it was shared with them."},"sharedWithYou":{"type":"boolean","description":"Whether the caller can read the page only through a share. Space and path stay hidden then."},"otherCategory":{"type":"boolean","description":"Whether the article lies in a category of a knowledge base that the caller may read but not change, while the caller is responsible for other categories there."},"path":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the page."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the page in the addresses of the app."},"title":{"type":"string","description":"Title of the page."}},"required":["id","number","title"],"additionalProperties":false,"description":"A parent page."},"description":"Parent pages the caller can read, from the top. Empty for shared pages."},"labels":{"type":"array","items":{"type":"string"},"description":"Labels of the page."},"status":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the status value."},"builtIn":{"anyOf":[{"type":"string","x-extensible-enum":["roughDraft","inProgress","readyForReview","verified"]},{"type":"null"}],"description":"Which default value this is, or null for a value a space admin added. Clients show the translated name of a default value unless `name` is set. New values can be added in later versions; handle unknown values."},"name":{"description":"Name set by a space admin, or null to show the default name.","type":["string","null"]},"color":{"type":"string","enum":["neutral","accent","info","success","warning","danger"],"description":"Color of the status: `neutral`, `accent`, `info`, `success`, `warning` or `danger`."}},"required":["id","builtIn","name","color"],"additionalProperties":false,"description":"A page status."},{"type":"null"}],"description":"Status of the page, or null when it has none or page status is turned off in the space."},"author":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the author."},"name":{"type":"string","description":"Name of the author."}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"The author, or null when unknown or not visible to the caller."},"archived":{"type":"boolean","description":"Whether the page is archived."},"attachment":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the attachment."},"name":{"type":"string","description":"File name."},"contentType":{"type":"string","description":"Media type of the file."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size in bytes."}},"required":["id","name","contentType","size"],"additionalProperties":false},{"type":"null"}],"description":"For an attachment, the file on its page; null otherwise."},"topic":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the running topic."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the running topic in the addresses of the app."},"title":{"type":"string","description":"Title of the running topic."}},"required":["id","number","title"],"additionalProperties":false,"description":"The running topic."},{"type":"null"}],"description":"For a topic, the running topic; for a decision, the topic it closed when the caller can read it; null otherwise."},"series":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the meeting series."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the meeting series in the addresses of the app."},"title":{"type":"string","description":"Title of the meeting series."}},"required":["id","number","title"],"additionalProperties":false,"description":"The meeting series."},{"type":"null"}],"description":"For a topic or decision, its meeting series when the caller can read it; null otherwise."},"updatedAt":{"type":"string","format":"date-time","description":"When the content last changed. ISO 8601 timestamp in UTC."}},"required":["type","id","itemId","number","itemType","title","heading","anchor","excerpt","space","sharedWithYou","otherCategory","path","labels","status","author","archived","attachment","topic","series","updatedAt"],"additionalProperties":false,"description":"A search result."},"description":"Results, in the requested order."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of results the caller can read, on all pages, up to the 1,000 best matches."},"totalCapped":{"type":"boolean","description":"True when the search has more matches than `total` counts. Show the number as \"1,000+\"; the results and counts cover the 1,000 most recently changed matches."},"nextCursor":{"description":"Cursor for the next page, or null on the last page.","type":["string","null"]},"facets":{"anyOf":[{"type":"object","properties":{"types":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string","description":"The type. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","blogPost","whiteboard","comment","attachment","topic","decision"]},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of results."}},"required":["value","count"],"additionalProperties":false,"description":"Type"},"description":"Types with their number of results."},"spaces":{"type":"array","items":{"type":"object","properties":{"id":{"anyOf":[{"type":"string","format":"uuid","description":"ID of the space."},{"type":"null"}],"description":"ID of the space, or null for pages shared with the caller."},"key":{"description":"Key of the space, or null.","type":["string","null"]},"name":{"description":"Name of the space, or null.","type":["string","null"]},"displayName":{"description":"Name to show, as `displayName` of a space in a result, or null.","type":["string","null"]},"personal":{"type":"boolean","description":"Whether this is a personal space."},"mine":{"type":"boolean","description":"Whether it is the caller's own personal space."},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of results."}},"required":["id","key","name","displayName","personal","mine","count"],"additionalProperties":false,"description":"A space."},"description":"Spaces with their number of results."},"labels":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string","description":"The label."},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of results."}},"required":["value","count"],"additionalProperties":false,"description":"Label"},"description":"Labels with their number of results."},"authors":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the author."},"name":{"type":"string","description":"Name of the author."},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of results."}},"required":["id","name","count"],"additionalProperties":false,"description":"An author."},"description":"Authors with their number of results."},"statuses":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the status value."},"builtIn":{"anyOf":[{"type":"string","x-extensible-enum":["roughDraft","inProgress","readyForReview","verified"]},{"type":"null"}],"description":"Which default value this is, or null for a value a space admin added. Clients show the translated name of a default value unless `name` is set. New values can be added in later versions; handle unknown values."},"name":{"description":"Name set by a space admin, or null to show the default name.","type":["string","null"]},"color":{"type":"string","enum":["neutral","accent","info","success","warning","danger"],"description":"Color of the status: `neutral`, `accent`, `info`, `success`, `warning` or `danger`."},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of results."}},"required":["id","builtIn","name","color","count"],"additionalProperties":false,"description":"A status value."},"description":"Status values with their number of results."},"languages":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string","description":"The content language code."},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of results."}},"required":["value","count"],"additionalProperties":false,"description":"Content language"},"description":"Content languages with their number of results."},"updated":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string","description":"Changed within the last `week` (7 days), `month` (30 days) or `year` (365 days). New values can be added in later versions; handle unknown values.","x-extensible-enum":["week","month","year"]},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of results."}},"required":["value","count"],"additionalProperties":false,"description":"Time range"},"description":"Time ranges with their number of results."}},"required":["types","spaces","labels","authors","statuses","languages","updated"],"additionalProperties":false},{"type":"null"}],"description":"Number of results per filter value, or null in quick search. Each group is counted as if its own filter were not set, so other values of a filter that is in use keep their counts. For a search with more than 1,000 matches the counts cover the 1,000 most recently changed matches, like `total`."},"suggestion":{"description":"The search text with misspelled words replaced by similar words from content the caller can read, or null when there is nothing to correct. Always null in quick search.","type":["string","null"]},"index":{"type":"object","properties":{"building":{"type":"boolean","description":"Whether the index is being built; results may be incomplete meanwhile."}},"required":["building"],"additionalProperties":false,"description":"State of the search index."}},"required":["results","total","totalCapped","nextCursor","facets","suggestion","index"],"additionalProperties":false,"description":"Search results."},"example":{"results":[{"type":"page","id":"01929b1e-7c1a-7000-8000-000000000020","itemId":"01929b1e-7c1a-7000-8000-000000000020","number":1042,"itemType":"page","title":"VPN access","heading":"Setup","anchor":"setup","excerpt":[{"text":"Install the ","highlighted":false},{"text":"WireGuard","highlighted":true},{"text":" client on your laptop.","highlighted":false}],"space":{"id":"01929b1e-7c1a-7000-8000-000000000010","key":"ITOPS","name":"IT Operations","displayName":"IT Operations","personal":false,"knowledgeBase":false,"mine":false},"sharedWithYou":false,"otherCategory":false,"path":[],"labels":["vpn"],"status":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","builtIn":"verified","name":null,"color":"success"},"author":{"id":"01929b1e-7c1a-7000-8000-000000000001","name":"Ada Lovelace"},"archived":false,"attachment":null,"topic":null,"series":null,"updatedAt":"2026-10-14T08:30:00.000Z"}],"total":1,"totalCapped":false,"nextCursor":null,"facets":{"types":[{"value":"page","count":1}],"spaces":[{"id":"01929b1e-7c1a-7000-8000-000000000010","key":"ITOPS","name":"IT Operations","displayName":"IT Operations","personal":false,"mine":false,"count":1}],"labels":[{"value":"vpn","count":1}],"authors":[{"id":"01929b1e-7c1a-7000-8000-000000000001","name":"Ada Lovelace","count":1}],"statuses":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","builtIn":"verified","name":null,"color":"success","count":1}],"languages":[{"value":"en","count":1}],"updated":[{"value":"week","count":1},{"value":"month","count":1},{"value":"year","count":1}]},"suggestion":null,"index":{"building":false}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests. `searchBusy`: Search is busy.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}},"searchBusy":{"value":{"type":"urn:lunedo:problem:searchBusy","title":"Search is busy","status":429,"code":"searchBusy"}}}}}},"503":{"description":"`searchTimedOut`: The search took too long.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"searchTimedOut":{"value":{"type":"urn:lunedo:problem:searchTimedOut","title":"The search took too long","status":503,"code":"searchTimedOut"}}}}}}}}},"/api/v1/organizations/{organizationId}/search/recent":{"delete":{"operationId":"savedSearches.forgetAll","summary":"Clear your recent searches","description":"Deletes all recent searches of the caller in the organization.\n\nRequires the permission `organization.search.manage` on the organization in `organizationId`.","tags":["Search"],"x-lunedo-permission":{"action":"organization.search.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"get":{"operationId":"savedSearches.recent","summary":"List your recent searches","description":"Lists the last 10 searches the caller ran in the organization, newest first. Only the caller sees them.\n\nRequires the permission `organization.search` on the organization in `organizationId`.","tags":["Search"],"x-lunedo-permission":{"action":"organization.search","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Recent searches.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the recent search."},"query":{"type":"string","description":"The search text."},"filters":{"type":"object","properties":{"spaceIds":{"default":[],"description":"ID of a spaces.","maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a space"}},"types":{"type":"array","items":{"type":"string","description":"A type: `page`, `blogPost`, `comment`, `attachment`, `topic` or `decision`. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","blogPost","whiteboard","comment","attachment","topic","decision"]},"description":"Types of results."},"labels":{"default":[],"description":"Labels.","maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":100,"description":"A label."}},"authorIds":{"default":[],"description":"ID of an authors.","maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"ID of an author"}},"statusIds":{"default":[],"description":"ID of a status values.","maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a status value"}},"languages":{"default":[],"description":"Content languages.","maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":20,"description":"A content language code, such as `en`."}},"updated":{"default":null,"description":"Changed within the last `week`, `month` (30 days) or `year` (365 days), or null for any time.","anyOf":[{"type":"string","enum":["week","month","year"]},{"type":"null"}]},"includeArchived":{"default":false,"description":"Whether archived pages are included.","type":"boolean"},"sort":{"default":"relevance","description":"`relevance` or `newest`.","type":"string","enum":["relevance","newest"]}},"required":["spaceIds","types","labels","authorIds","statusIds","languages","updated","includeArchived","sort"],"additionalProperties":false,"description":"Filters of a search, as on the search page."},"searchedAt":{"type":"string","format":"date-time","description":"When the caller last ran this search. ISO 8601 timestamp in UTC."}},"required":["id","query","filters","searchedAt"],"additionalProperties":false,"description":"A recent search."},"description":"Up to 10 searches, newest first."},"example":[{"id":"01929b1e-7c1a-7000-8000-000000000031","query":"vpn gateway","filters":{"spaceIds":[],"types":["page"],"labels":["runbook"],"authorIds":[],"statusIds":[],"languages":[],"updated":"month","includeArchived":false,"sort":"relevance"},"searchedAt":"2026-10-14T08:30:00.000Z"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"savedSearches.remember","summary":"Remember a search","description":"Adds a search to the caller's recent searches, or moves it to the top when it is there already. Only the last 10 are kept. An empty query is not remembered.\n\nRequires the permission `organization.search.manage` on the organization in `organizationId`.","tags":["Search"],"x-lunedo-permission":{"action":"organization.search.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string","maxLength":500,"description":"The search text, with operators."},"filters":{"type":"object","properties":{"spaceIds":{"default":[],"description":"ID of a spaces.","maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a space"}},"types":{"default":[],"description":"Types of results.","maxItems":7,"type":"array","items":{"type":"string","enum":["page","blogPost","whiteboard","comment","attachment","topic","decision"],"description":"A type: `page`, `blogPost`, `comment`, `attachment`, `topic` or `decision`."}},"labels":{"default":[],"description":"Labels.","maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":100,"description":"A label."}},"authorIds":{"default":[],"description":"ID of an authors.","maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"ID of an author"}},"statusIds":{"default":[],"description":"ID of a status values.","maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a status value"}},"languages":{"default":[],"description":"Content languages.","maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":20,"description":"A content language code, such as `en`."}},"updated":{"default":null,"description":"Changed within the last `week`, `month` (30 days) or `year` (365 days), or null for any time.","anyOf":[{"type":"string","enum":["week","month","year"]},{"type":"null"}]},"includeArchived":{"default":false,"description":"Whether archived pages are included.","type":"boolean"},"sort":{"default":"relevance","description":"`relevance` or `newest`.","type":"string","enum":["relevance","newest"]}},"additionalProperties":false,"description":"Filters of a search, as on the search page."}},"required":["query","filters"],"additionalProperties":false,"description":"A search the caller ran."},"example":{"query":"vpn gateway","filters":{"spaceIds":[],"types":["page"],"labels":["runbook"],"authorIds":[],"statusIds":[],"languages":[],"updated":"month","includeArchived":false,"sort":"relevance"}}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/search/recent/{searchId}":{"delete":{"operationId":"savedSearches.forget","summary":"Delete a recent search","description":"Deletes one of the caller's recent searches.\n\nRequires the permission `organization.search.manage` on the organization in `organizationId`.","tags":["Search"],"x-lunedo-permission":{"action":"organization.search.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"searchId","in":"path","required":true,"description":"ID of the recent search.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/search/saved":{"get":{"operationId":"savedSearches.saved","summary":"List your saved searches","description":"Lists the searches the caller saved in the organization. Only the caller sees them.\n\nRequires the permission `organization.search` on the organization in `organizationId`.","tags":["Search"],"x-lunedo-permission":{"action":"organization.search","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Saved searches.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the saved search."},"name":{"type":"string","description":"Name of the saved search."},"query":{"type":"string","description":"The search text."},"filters":{"type":"object","properties":{"spaceIds":{"default":[],"description":"ID of a spaces.","maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a space"}},"types":{"type":"array","items":{"type":"string","description":"A type: `page`, `blogPost`, `comment`, `attachment`, `topic` or `decision`. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","blogPost","whiteboard","comment","attachment","topic","decision"]},"description":"Types of results."},"labels":{"default":[],"description":"Labels.","maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":100,"description":"A label."}},"authorIds":{"default":[],"description":"ID of an authors.","maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"ID of an author"}},"statusIds":{"default":[],"description":"ID of a status values.","maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a status value"}},"languages":{"default":[],"description":"Content languages.","maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":20,"description":"A content language code, such as `en`."}},"updated":{"default":null,"description":"Changed within the last `week`, `month` (30 days) or `year` (365 days), or null for any time.","anyOf":[{"type":"string","enum":["week","month","year"]},{"type":"null"}]},"includeArchived":{"default":false,"description":"Whether archived pages are included.","type":"boolean"},"sort":{"default":"relevance","description":"`relevance` or `newest`.","type":"string","enum":["relevance","newest"]}},"required":["spaceIds","types","labels","authorIds","statusIds","languages","updated","includeArchived","sort"],"additionalProperties":false,"description":"Filters of a search, as on the search page."},"createdAt":{"type":"string","format":"date-time","description":"When the search was saved. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the saved search last changed. ISO 8601 timestamp in UTC."}},"required":["id","name","query","filters","createdAt","updatedAt"],"additionalProperties":false,"description":"A saved search. It stores the query and filters, never results."},"description":"Saved searches, ordered by name."},"example":[{"id":"01929b1e-7c1a-7000-8000-000000000032","name":"Runbooks to verify","query":"status:draft","filters":{"spaceIds":[],"types":["page"],"labels":["runbook"],"authorIds":[],"statusIds":[],"languages":[],"updated":"month","includeArchived":false,"sort":"relevance"},"createdAt":"2026-10-14T08:30:00.000Z","updatedAt":"2026-10-14T08:30:00.000Z"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"savedSearches.save","summary":"Save a search","description":"Saves a query with its filters under a name for the caller. Running it later shows what the caller can read at that time. Up to 100 per person and organization.\n\nRequires the permission `organization.search.manage` on the organization in `organizationId`.","tags":["Search"],"x-lunedo-permission":{"action":"organization.search.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Name of the saved search, 1 to 100 characters."},"query":{"type":"string","maxLength":500,"description":"The search text, with operators."},"filters":{"type":"object","properties":{"spaceIds":{"default":[],"description":"ID of a spaces.","maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a space"}},"types":{"default":[],"description":"Types of results.","maxItems":7,"type":"array","items":{"type":"string","enum":["page","blogPost","whiteboard","comment","attachment","topic","decision"],"description":"A type: `page`, `blogPost`, `comment`, `attachment`, `topic` or `decision`."}},"labels":{"default":[],"description":"Labels.","maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":100,"description":"A label."}},"authorIds":{"default":[],"description":"ID of an authors.","maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"ID of an author"}},"statusIds":{"default":[],"description":"ID of a status values.","maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a status value"}},"languages":{"default":[],"description":"Content languages.","maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":20,"description":"A content language code, such as `en`."}},"updated":{"default":null,"description":"Changed within the last `week`, `month` (30 days) or `year` (365 days), or null for any time.","anyOf":[{"type":"string","enum":["week","month","year"]},{"type":"null"}]},"includeArchived":{"default":false,"description":"Whether archived pages are included.","type":"boolean"},"sort":{"default":"relevance","description":"`relevance` or `newest`.","type":"string","enum":["relevance","newest"]}},"additionalProperties":false,"description":"Filters of a search, as on the search page."}},"required":["name","query","filters"],"additionalProperties":false,"description":"A search to save."},"example":{"name":"Runbooks to verify","query":"status:draft","filters":{"spaceIds":[],"types":["page"],"labels":["runbook"],"authorIds":[],"statusIds":[],"languages":[],"updated":"month","includeArchived":false,"sort":"relevance"}}}}},"responses":{"201":{"description":"The saved search.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the saved search."},"name":{"type":"string","description":"Name of the saved search."},"query":{"type":"string","description":"The search text."},"filters":{"type":"object","properties":{"spaceIds":{"default":[],"description":"ID of a spaces.","maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a space"}},"types":{"type":"array","items":{"type":"string","description":"A type: `page`, `blogPost`, `comment`, `attachment`, `topic` or `decision`. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","blogPost","whiteboard","comment","attachment","topic","decision"]},"description":"Types of results."},"labels":{"default":[],"description":"Labels.","maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":100,"description":"A label."}},"authorIds":{"default":[],"description":"ID of an authors.","maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"ID of an author"}},"statusIds":{"default":[],"description":"ID of a status values.","maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a status value"}},"languages":{"default":[],"description":"Content languages.","maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":20,"description":"A content language code, such as `en`."}},"updated":{"default":null,"description":"Changed within the last `week`, `month` (30 days) or `year` (365 days), or null for any time.","anyOf":[{"type":"string","enum":["week","month","year"]},{"type":"null"}]},"includeArchived":{"default":false,"description":"Whether archived pages are included.","type":"boolean"},"sort":{"default":"relevance","description":"`relevance` or `newest`.","type":"string","enum":["relevance","newest"]}},"required":["spaceIds","types","labels","authorIds","statusIds","languages","updated","includeArchived","sort"],"additionalProperties":false,"description":"Filters of a search, as on the search page."},"createdAt":{"type":"string","format":"date-time","description":"When the search was saved. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the saved search last changed. ISO 8601 timestamp in UTC."}},"required":["id","name","query","filters","createdAt","updatedAt"],"additionalProperties":false,"description":"A saved search. It stores the query and filters, never results."},"example":{"id":"01929b1e-7c1a-7000-8000-000000000032","name":"Runbooks to verify","query":"status:draft","filters":{"spaceIds":[],"types":["page"],"labels":["runbook"],"authorIds":[],"statusIds":[],"languages":[],"updated":"month","includeArchived":false,"sort":"relevance"},"createdAt":"2026-10-14T08:30:00.000Z","updatedAt":"2026-10-14T08:30:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`tooManySavedSearches`: Too many saved searches.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"tooManySavedSearches":{"value":{"type":"urn:lunedo:problem:tooManySavedSearches","title":"Too many saved searches","status":409,"code":"tooManySavedSearches"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/search/saved/{searchId}":{"delete":{"operationId":"savedSearches.remove","summary":"Delete a saved search","description":"Deletes one of the caller's saved searches.\n\nRequires the permission `organization.search.manage` on the organization in `organizationId`.","tags":["Search"],"x-lunedo-permission":{"action":"organization.search.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"searchId","in":"path","required":true,"description":"ID of the saved search.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"patch":{"operationId":"savedSearches.update","summary":"Change a saved search","description":"Renames a saved search of the caller or replaces its query or filters.\n\nRequires the permission `organization.search.manage` on the organization in `organizationId`.","tags":["Search"],"x-lunedo-permission":{"action":"organization.search.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"searchId","in":"path","required":true,"description":"ID of the saved search.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Name of the saved search, 1 to 100 characters."},"query":{"type":"string","maxLength":500,"description":"The search text, with operators."},"filters":{"type":"object","properties":{"spaceIds":{"default":[],"description":"ID of a spaces.","maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a space"}},"types":{"default":[],"description":"Types of results.","maxItems":7,"type":"array","items":{"type":"string","enum":["page","blogPost","whiteboard","comment","attachment","topic","decision"],"description":"A type: `page`, `blogPost`, `comment`, `attachment`, `topic` or `decision`."}},"labels":{"default":[],"description":"Labels.","maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":100,"description":"A label."}},"authorIds":{"default":[],"description":"ID of an authors.","maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"ID of an author"}},"statusIds":{"default":[],"description":"ID of a status values.","maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a status value"}},"languages":{"default":[],"description":"Content languages.","maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":20,"description":"A content language code, such as `en`."}},"updated":{"default":null,"description":"Changed within the last `week`, `month` (30 days) or `year` (365 days), or null for any time.","anyOf":[{"type":"string","enum":["week","month","year"]},{"type":"null"}]},"includeArchived":{"default":false,"description":"Whether archived pages are included.","type":"boolean"},"sort":{"default":"relevance","description":"`relevance` or `newest`.","type":"string","enum":["relevance","newest"]}},"additionalProperties":false,"description":"Filters of a search, as on the search page."}},"additionalProperties":false,"description":"Fields to change."},"example":{"name":"Verify runbooks"}}}},"responses":{"200":{"description":"The saved search.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the saved search."},"name":{"type":"string","description":"Name of the saved search."},"query":{"type":"string","description":"The search text."},"filters":{"type":"object","properties":{"spaceIds":{"default":[],"description":"ID of a spaces.","maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a space"}},"types":{"type":"array","items":{"type":"string","description":"A type: `page`, `blogPost`, `comment`, `attachment`, `topic` or `decision`. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","blogPost","whiteboard","comment","attachment","topic","decision"]},"description":"Types of results."},"labels":{"default":[],"description":"Labels.","maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":100,"description":"A label."}},"authorIds":{"default":[],"description":"ID of an authors.","maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"ID of an author"}},"statusIds":{"default":[],"description":"ID of a status values.","maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a status value"}},"languages":{"default":[],"description":"Content languages.","maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":20,"description":"A content language code, such as `en`."}},"updated":{"default":null,"description":"Changed within the last `week`, `month` (30 days) or `year` (365 days), or null for any time.","anyOf":[{"type":"string","enum":["week","month","year"]},{"type":"null"}]},"includeArchived":{"default":false,"description":"Whether archived pages are included.","type":"boolean"},"sort":{"default":"relevance","description":"`relevance` or `newest`.","type":"string","enum":["relevance","newest"]}},"required":["spaceIds","types","labels","authorIds","statusIds","languages","updated","includeArchived","sort"],"additionalProperties":false,"description":"Filters of a search, as on the search page."},"createdAt":{"type":"string","format":"date-time","description":"When the search was saved. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the saved search last changed. ISO 8601 timestamp in UTC."}},"required":["id","name","query","filters","createdAt","updatedAt"],"additionalProperties":false,"description":"A saved search. It stores the query and filters, never results."},"example":{"id":"01929b1e-7c1a-7000-8000-000000000032","name":"Runbooks to verify","query":"status:draft","filters":{"spaceIds":[],"types":["page"],"labels":["runbook"],"authorIds":[],"statusIds":[],"languages":[],"updated":"month","includeArchived":false,"sort":"relevance"},"createdAt":"2026-10-14T08:30:00.000Z","updatedAt":"2026-10-14T08:30:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/service-accounts":{"get":{"operationId":"serviceAccounts.list","summary":"List service accounts","description":"Lists the service accounts of the organization, active and deactivated. Service accounts without a responsible person are marked as `unattended`.\n\nRequires the permission `organization.integrations.view` on the organization in `organizationId`.","tags":["Service accounts"],"x-lunedo-permission":{"action":"organization.integrations.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"Service accounts of the organization.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the service account. Use it as account ID in role assignments and groups."},"organizationId":{"type":"string","format":"uuid","description":"ID of the organization that owns the service account."},"name":{"type":"string","description":"Display name, 1 to 200 characters."},"description":{"type":"string","description":"What the service account is for, up to 1000 characters."},"state":{"type":"string","description":"`active` or `deactivated`."},"responsibleAccountIds":{"type":"array","items":{"type":"string","format":"uuid","description":"ID of a responsible member."},"description":"Members who receive reminders and notices about the service account. They grant no permissions and limit none."},"unattended":{"type":"boolean","description":"True when the service account has no responsible person. Its permissions stay unchanged."},"createdAt":{"type":"string","format":"date-time","description":"When the service account was created. ISO 8601 timestamp in UTC."}},"required":["id","organizationId","name","description","state","responsibleAccountIds","unattended","createdAt"],"additionalProperties":false,"description":"An account for scripts and integrations, without password or sign-in."},"description":"Service accounts, ordered by name."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"One page of results."},"example":{"items":[{"id":"01929b1f-3da0-7d84-b5a1-9c8d7e6fb0c1","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","name":"Release bot","description":"Publishes release notes","state":"active","responsibleAccountIds":["01929b1e-8d4b-7e3f-a05c-4d3e2f1a6b7c"],"unattended":false,"createdAt":"2026-10-01T08:00:00.000Z"}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"serviceAccounts.create","summary":"Create a service account","description":"Creates an account for scripts and integrations. It has no password and cannot sign in; it acts only through API tokens. Its permissions come only from the roles and groups it is given. The creator becomes its responsible person unless a list is given.\n\nRequires the permission `organization.integrations.manage` on the organization in `organizationId`.","tags":["Service accounts"],"x-lunedo-permission":{"action":"organization.integrations.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"Display name, 1 to 200 characters."},"description":{"description":"What it is for, up to 1000 characters.","type":"string","maxLength":1000},"responsibleAccountIds":{"maxItems":20,"type":"array","items":{"type":"string","format":"uuid"},"description":"Members who receive reminders and notices, up to 20. They grant no permissions. The caller when left out; an empty list for nobody."}},"required":["name"],"additionalProperties":false,"description":"A new service account."},"example":{"name":"Release bot","description":"Publishes release notes"}}}},"responses":{"201":{"description":"The new service account.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the service account. Use it as account ID in role assignments and groups."},"organizationId":{"type":"string","format":"uuid","description":"ID of the organization that owns the service account."},"name":{"type":"string","description":"Display name, 1 to 200 characters."},"description":{"type":"string","description":"What the service account is for, up to 1000 characters."},"state":{"type":"string","description":"`active` or `deactivated`."},"responsibleAccountIds":{"type":"array","items":{"type":"string","format":"uuid","description":"ID of a responsible member."},"description":"Members who receive reminders and notices about the service account. They grant no permissions and limit none."},"unattended":{"type":"boolean","description":"True when the service account has no responsible person. Its permissions stay unchanged."},"createdAt":{"type":"string","format":"date-time","description":"When the service account was created. ISO 8601 timestamp in UTC."}},"required":["id","organizationId","name","description","state","responsibleAccountIds","unattended","createdAt"],"additionalProperties":false,"description":"An account for scripts and integrations, without password or sign-in."},"example":{"id":"01929b1f-3da0-7d84-b5a1-9c8d7e6fb0c1","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","name":"Release bot","description":"Publishes release notes","state":"active","responsibleAccountIds":["01929b1e-8d4b-7e3f-a05c-4d3e2f1a6b7c"],"unattended":false,"createdAt":"2026-10-01T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidResponsible`: The responsible person is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidResponsible":{"value":{"type":"urn:lunedo:problem:invalidResponsible","title":"The responsible person is not valid","status":400,"code":"invalidResponsible"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/settings":{"get":{"operationId":"organizations.settings","summary":"List settings","description":"Lists the settings that can be set for the organization, with their effective values.\n\nRequires the permission `organization.settings.view` on the organization in `organizationId`.","tags":["Settings"],"x-lunedo-permission":{"action":"organization.settings.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"Settings of the organization.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the setting."},"value":{"description":"Effective value at this level.","$ref":"#/components/schemas/Schema113ae44d8375"},"defaultValue":{"description":"Value that applies when no level sets one.","$ref":"#/components/schemas/Schemafbc378f59d82"},"source":{"type":"string","description":"Level the effective value comes from, or `default`."},"lockedBy":{"description":"Higher level that locked the setting, or null.","type":["string","null"]},"locked":{"type":"boolean","description":"Whether this level locks the setting for lower levels."},"lockable":{"type":"boolean","description":"Whether the setting can be locked."},"levelsBelow":{"type":"array","items":{"type":"string"},"description":"Lower levels where the setting can be set. A lock at this level applies to them."},"editable":{"type":"boolean","description":"Whether the setting can be changed through the settings endpoint."},"stricterOnly":{"anyOf":[{"type":"string","enum":["lower","higher"]},{"type":"null"}],"description":"For a limit: `lower` when lower levels may only choose a lower value, `higher` when only a higher one, null otherwise. The value inherited from above is the bound."},"maximum":{"description":"Highest value allowed, set for the instance, or null when the setting has no maximum. `unlimited` allows any value.","$ref":"#/components/schemas/Schema682d67ac39ef"},"minimum":{"description":"Lowest value allowed, set for the instance, or null when the setting has no minimum.","type":["number","null"]},"levels":{"type":"array","items":{"type":"object","properties":{"level":{"type":"string","description":"The level: `instance`, `organization`, `space` or `user`."},"value":{"description":"Value stored at this level, or null.","$ref":"#/components/schemas/Schema1a810d563c56"},"locked":{"type":"boolean","description":"Whether this level locks the setting."},"effective":{"type":"boolean","description":"False when a lock above or a stricter value above makes this level's value ineffective."}},"required":["level","value","locked","effective"],"additionalProperties":false,"description":"The state of the setting at one level."},"description":"Every level the setting applies to, from the instance down to this level."}},"required":["key","value","defaultValue","source","lockedBy","locked","lockable","levelsBelow","editable","stricterOnly","maximum","minimum","levels"],"additionalProperties":false,"description":"A setting with its effective value and where it comes from."},"description":"Settings, ordered by key."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"One page of results."},"example":{"items":[{"key":"auth.passwordMinLength","value":14,"defaultValue":12,"source":"instance","lockedBy":null,"locked":false,"lockable":true,"levelsBelow":["organization"],"editable":true,"stricterOnly":"higher","maximum":null,"minimum":null,"levels":[{"level":"instance","value":14,"locked":false,"effective":true},{"level":"organization","value":null,"locked":false,"effective":true}]}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/settings/{key}":{"put":{"operationId":"organizations.updateSettings","summary":"Change a setting","description":"Sets, clears or locks a setting for the organization. Sign-in settings need the sign-in and security area, all others the settings area.\n\nRequires one of the permissions `organization.settings.manage`, `organization.signIn.manage` on the organization in `organizationId`; the request decides which.","tags":["Settings"],"x-lunedo-permission":{"action":"organization.settings.manage","alternatives":["organization.signIn.manage"],"resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"key","in":"path","required":true,"description":"Key of the setting.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"value":{"description":"New value. Its type depends on the setting.","$ref":"#/components/schemas/Schema113ae44d8375"},"clear":{"description":"Remove the value at this level, so the level above applies.","type":"boolean","const":true},"locked":{"description":"Lock or unlock the setting for the levels below.","type":"boolean"}},"additionalProperties":false,"description":"A change to a setting. Send at least one field."},"example":{"value":true}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidSetting`: The setting value is not valid. `settingAboveMaximum`: The value is above the maximum set for the instance. `settingManagedElsewhere`: The setting is changed through another endpoint.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidSetting":{"value":{"type":"urn:lunedo:problem:invalidSetting","title":"The setting value is not valid","status":400,"code":"invalidSetting"}},"settingAboveMaximum":{"value":{"type":"urn:lunedo:problem:settingAboveMaximum","title":"The value is above the maximum set for the instance","status":400,"code":"settingAboveMaximum"}},"settingManagedElsewhere":{"value":{"type":"urn:lunedo:problem:settingManagedElsewhere","title":"The setting is changed through another endpoint","status":400,"code":"settingManagedElsewhere"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`settingLocked`: A higher level locked the setting. `settingNotAtLevel`: The setting cannot be set at this level.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"settingLocked":{"value":{"type":"urn:lunedo:problem:settingLocked","title":"A higher level locked the setting","status":409,"code":"settingLocked"}},"settingNotAtLevel":{"value":{"type":"urn:lunedo:problem:settingNotAtLevel","title":"The setting cannot be set at this level","status":409,"code":"settingNotAtLevel"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/space-cleanup":{"get":{"operationId":"spaceCleanup.list","summary":"List protected spaces to clean up","description":"Lists personal, one-on-one and confidential spaces of the organization in which no active member remains and that have stayed so for the waiting period of the organization (at least 7 days). Shows key, kind, size, pages, last activity and former members; names, titles and content stay hidden. Personal spaces count for the home organization of their owner.\n\nRequires the permission `organization.spaces.manage` on the organization in `organizationId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"organization.spaces.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"Spaces to clean up and the waiting period.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"kind":{"type":"string","enum":["personal","oneOnOne","confidential"],"description":"`personal` for a personal space of someone whose home organization this is, `oneOnOne` or `confidential`."},"storageBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of all files attached in the space, in bytes."},"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages and blog posts in the space, without the trash."},"lastActivityAt":{"type":"string","format":"date-time","description":"When content in the space last changed. ISO 8601 timestamp in UTC."},"orphanedAt":{"type":"string","format":"date-time","description":"When the last active member left the space. ISO 8601 timestamp in UTC."},"formerMembers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false,"description":"A former member."},"description":"People who held a role in the space, ordered by name. None of them is active anymore."}},"required":["id","key","kind","storageBytes","pages","lastActivityAt","orphanedAt","formerMembers"],"additionalProperties":false,"description":"A protected space without active members, as organization administrators see it: no name or content."},"description":"Spaces to clean up, ordered by key."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]},"graceDays":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Days a space stays without active members before it appears here."}},"required":["items","nextCursor","graceDays"],"additionalProperties":false},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5b00","key":"MSAB","kind":"confidential","storageBytes":1048576,"pages":12,"lastActivityAt":"2026-08-01T15:00:00.000Z","orphanedAt":"2026-09-01T08:00:00.000Z","formerMembers":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"}]}],"nextCursor":null,"graceDays":30}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/space-cleanup/{spaceId}/delete":{"post":{"operationId":"spaceCleanup.delete","summary":"Delete a protected space without members","description":"Deletes a space from the clean-up list without reading it. It goes to the second stage of the trash and is deleted permanently when its retention period ends; until then the people who were its space admins, and for personal spaces the instance administrators, can restore it. Requires typing the key and a reason, which goes into the audit log. Needs a signed-in session; API tokens are refused.\n\nRequires the permission `organization.spaces.manage` on the organization in `organizationId`. Needs a signed-in session; API tokens are refused.","tags":["Spaces"],"x-lunedo-permission":{"action":"organization.spaces.manage","resource":"organization","parameter":"organizationId"},"security":[{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"confirmation":{"type":"string","maxLength":40,"description":"The key of the space, typed exactly."},"reason":{"type":"string","maxLength":1000,"description":"Why the space is deleted, 1 to 500 characters; it goes into the audit log."}},"required":["confirmation","reason"],"additionalProperties":false,"description":"Confirmation and reason."},"example":{"confirmation":"MSAB","reason":"Both people left the company"}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`confirmationMismatch`: The confirmation does not match. `invalidInput`: The request is not valid. `reasonRequired`: A reason is required.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"confirmationMismatch":{"value":{"type":"urn:lunedo:problem:confirmationMismatch","title":"The confirmation does not match","status":400,"code":"confirmationMismatch"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"reasonRequired":{"value":{"type":"urn:lunedo:problem:reasonRequired","title":"A reason is required","status":400,"code":"reasonRequired"}}}}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `reauthenticationRequired`: Confirm your identity first. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"reauthenticationRequired":{"value":{"type":"urn:lunedo:problem:reauthenticationRequired","title":"Confirm your identity first","status":403,"code":"reauthenticationRequired"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notInCleanup`: The space is not up for clean-up.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notInCleanup":{"value":{"type":"urn:lunedo:problem:notInCleanup","title":"The space is not up for clean-up","status":409,"code":"notInCleanup"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/space-defaults":{"get":{"operationId":"organizationSpaces.defaults","summary":"Get the default permissions for new spaces","description":"Returns the visibility and roles a new space of the organization gets unless its creator changes them.\n\nRequires one of the permissions `organization.spaces.create`, `organization.settings.view` on the organization in `organizationId`; the request decides which.","tags":["Spaces"],"x-lunedo-permission":{"action":"organization.spaces.create","alternatives":["organization.settings.view"],"resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The default permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"visibility":{"type":"string","enum":["private","organization","instance"],"description":"Who can read the space besides its holders: `private` (only holders), `organization` (every member of the organization) or `instance` (every internal user of the instance)."},"grants":{"type":"array","items":{"type":"object","properties":{"principalKind":{"type":"string","enum":["account","group","organizationMembers","instanceUsers"],"description":"Holder of a role: an account (person or service account), a group, all members of the organization, or all internal users of the instance."},"principalId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the account or group, or null."},"role":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},"name":{"description":"Name of the account or group, or null for the other holders.","type":["string","null"]}},"required":["principalKind","principalId","role","name"],"additionalProperties":false,"description":"A default role with the holder's name."},"description":"Roles a new space gets unless the creator changes them."}},"required":["visibility","grants"],"additionalProperties":false,"description":"Default permissions for new spaces of the organization."},"example":{"visibility":"organization","grants":[{"principalKind":"organizationMembers","principalId":null,"role":"editor","name":null}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"put":{"operationId":"organizationSpaces.setDefaults","summary":"Change the default permissions for new spaces","description":"Sets the visibility and roles new spaces get. Existing spaces do not change. The change is audited as a settings change.\n\nRequires the permission `organization.settings.manage` on the organization in `organizationId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"organization.settings.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"visibility":{"type":"string","enum":["private","organization","instance"],"description":"Who can read the space besides its holders: `private` (only holders), `organization` (every member of the organization) or `instance` (every internal user of the instance)."},"grants":{"maxItems":50,"type":"array","items":{"type":"object","properties":{"principalKind":{"type":"string","enum":["account","group","organizationMembers","instanceUsers"],"description":"Holder of a role: an account (person or service account), a group, all members of the organization, or all internal users of the instance."},"principalId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the account or group; null for all members and all internal users."},"role":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."}},"required":["principalKind","principalId","role"],"additionalProperties":false,"description":"A role for a holder."},"description":"Roles a new space gets unless the creator changes them."}},"required":["visibility","grants"],"additionalProperties":false,"description":"Default permissions for new spaces."},"example":{"visibility":"organization","grants":[{"principalKind":"organizationMembers","principalId":null,"role":"reader"}]}}}},"responses":{"200":{"description":"The default permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"visibility":{"type":"string","enum":["private","organization","instance"],"description":"Who can read the space besides its holders: `private` (only holders), `organization` (every member of the organization) or `instance` (every internal user of the instance)."},"grants":{"type":"array","items":{"type":"object","properties":{"principalKind":{"type":"string","enum":["account","group","organizationMembers","instanceUsers"],"description":"Holder of a role: an account (person or service account), a group, all members of the organization, or all internal users of the instance."},"principalId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the account or group, or null."},"role":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},"name":{"description":"Name of the account or group, or null for the other holders.","type":["string","null"]}},"required":["principalKind","principalId","role","name"],"additionalProperties":false,"description":"A default role with the holder's name."},"description":"Roles a new space gets unless the creator changes them."}},"required":["visibility","grants"],"additionalProperties":false,"description":"Default permissions for new spaces of the organization."},"example":{"visibility":"organization","grants":[{"principalKind":"organizationMembers","principalId":null,"role":"reader","name":null}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid. `portalAccountReaderOnly`: Portal accounts can only read.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"portalAccountReaderOnly":{"value":{"type":"urn:lunedo:problem:portalAccountReaderOnly","title":"Portal accounts can only read","status":400,"code":"portalAccountReaderOnly"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`privateSpaceBroadGrant`: A private space gives roles to people and groups only.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"privateSpaceBroadGrant":{"value":{"type":"urn:lunedo:problem:privateSpaceBroadGrant","title":"A private space gives roles to people and groups only","status":409,"code":"privateSpaceBroadGrant"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/space-key-suggestion":{"get":{"operationId":"organizationSpaces.suggestKey","summary":"Suggest a key for a new space","description":"Suggests a free key derived from the name of the new space.\n\nRequires the permission `organization.spaces.create` on the organization in `organizationId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"organization.spaces.create","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"name","in":"query","required":true,"description":"Name of the new space.","schema":{"type":"string","minLength":1,"maxLength":100}}],"responses":{"200":{"description":"The suggested key.","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"The key in its stored form, in capitals."},"valid":{"type":"boolean","description":"Whether the key has 2 to 10 letters or digits."},"available":{"type":"boolean","description":"Whether no other space uses the key."}},"required":["key","valid","available"],"additionalProperties":false,"description":"A key for a new space."},"example":{"key":"ITO","valid":true,"available":true}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/space-keys/{key}":{"get":{"operationId":"organizationSpaces.checkKey","summary":"Check a key for a new space","description":"Tells whether a key is valid and free.\n\nRequires the permission `organization.spaces.create` on the organization in `organizationId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"organization.spaces.create","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"key","in":"path","required":true,"description":"Key to check.","schema":{"type":"string","maxLength":20}}],"responses":{"200":{"description":"Whether the key can be used.","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"The key in its stored form, in capitals."},"valid":{"type":"boolean","description":"Whether the key has 2 to 10 letters or digits."},"available":{"type":"boolean","description":"Whether no other space uses the key."}},"required":["key","valid","available"],"additionalProperties":false,"description":"A key for a new space."},"example":{"key":"ITOPS","valid":true,"available":false}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/spaces":{"get":{"operationId":"organizationSpaces.organizationSpaces","summary":"List the spaces of an organization","description":"Lists every space of the organization except personal spaces and one-on-one spaces, with its space admins, size and last activity. Confidential spaces appear with their key only.\n\nRequires the permission `organization.spaces.view` on the organization in `organizationId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"organization.spaces.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}},{"name":"q","in":"query","required":false,"description":"Only items that contain this text, ignoring case: in the name and e-mail address of accounts and members, the name and short name of organizations, and the name and description of groups.","schema":{"type":"string","maxLength":200}},{"name":"type","in":"query","required":false,"description":"Only spaces of this type.","schema":{"type":"string","enum":["standard","knowledgeBase"]}},{"name":"state","in":"query","required":false,"description":"Only active or only archived spaces.","schema":{"type":"string","enum":["active","archived"]}}],"responses":{"200":{"description":"Spaces of the organization.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"name":{"description":"Name of the space, or null for a confidential space, whose name administrators do not see.","type":["string","null"]},"type":{"type":"string","description":"`standard` or `knowledgeBase`."},"visibility":{"type":"string","enum":["private","organization","instance"],"description":"Who can read the space besides its holders: `private` (only holders), `organization` (every member of the organization) or `instance` (every internal user of the instance)."},"confidential":{"type":"boolean","description":"Whether the space is confidential."},"archived":{"type":"boolean","description":"Whether the space is archived."},"administrators":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["account","group"],"description":"Whether a person or a group holds the role."},"id":{"type":"string","format":"uuid","description":"ID of the account or group."},"name":{"type":"string","description":"Name of the account or group."}},"required":["kind","id","name"],"additionalProperties":false,"description":"A holder of the space admin role."},"description":"Space admins, ordered by name. Empty for confidential spaces."},"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages and blog posts in the space, without the trash."},"storageBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of all files attached in the space, in bytes."},"lastActivityAt":{"type":"string","format":"date-time","description":"When content in the space last changed. ISO 8601 timestamp in UTC."},"canManage":{"type":"boolean","description":"Whether the caller may change the settings of the space and archive it."},"canDelete":{"type":"boolean","description":"Whether the caller may delete the space."}},"required":["id","key","name","type","visibility","confidential","archived","administrators","pages","storageBytes","lastActivityAt","canManage","canDelete"],"additionalProperties":false,"description":"A space of the organization as administrators see it."},"description":"Spaces, ordered by name."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"One page of results."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","key":"ITOPS","name":"IT Operations","type":"standard","visibility":"organization","confidential":false,"archived":false,"administrators":[{"kind":"account","id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Ada Lovelace"}],"pages":42,"storageBytes":1048576,"lastActivityAt":"2026-10-24T08:15:00.000Z","canManage":true,"canDelete":true}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"organizationSpaces.create","summary":"Create a space","description":"Creates a space. A standard space starts with an overview page; a knowledge base starts empty and holds articles in categories. The creator becomes space admin; the given holders get their roles. Members can create spaces when the organization allows it; guests and collaborators cannot.\n\nRequires the permission `organization.spaces.create` on the organization in `organizationId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"organization.spaces.create","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"description":"Name, 1 to 100 characters."},"key":{"type":"string","maxLength":20,"description":"Key, 2 to 10 letters or digits; it is stored in capitals."},"description":{"description":"Short description, up to 1000 characters.","type":"string","maxLength":1000},"visibility":{"description":"Who can read the space besides its holders. Required for standard spaces; a knowledge base takes it from `audience`.","type":"string","enum":["private","organization","instance"]},"type":{"default":"standard","type":"string","description":"Type of the space: `standard` for pages, blog posts, meetings and whiteboards, or `knowledgeBase` for articles in categories. Chosen at creation. New values can be added in later versions; handle unknown values.","x-extensible-enum":["standard","knowledgeBase"]},"audience":{"description":"Who may read a knowledge base. Default `signedIn`. Only for knowledge bases.","type":"string","x-extensible-enum":["public","signedIn","groups","portal"]},"confidential":{"default":false,"description":"Create a confidential space. It must be private, and only individual people can hold roles. This cannot be changed later.","type":"boolean"},"grants":{"maxItems":100,"type":"array","items":{"type":"object","properties":{"principalKind":{"type":"string","enum":["account","group","organizationMembers","instanceUsers"],"description":"Holder of a role: an account (person or service account), a group, all members of the organization, or all internal users of the instance."},"principalId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the account or group; null for all members and all internal users."},"role":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."}},"required":["principalKind","principalId","role"],"additionalProperties":false,"description":"A role for a holder."},"description":"Roles for holders. The creator always becomes space admin in addition."}},"required":["name","key","grants"],"additionalProperties":false,"description":"A new space."},"example":{"name":"IT Operations","key":"ITOPS","description":"Runbooks and how-tos of the IT team","visibility":"organization","grants":[{"principalKind":"organizationMembers","principalId":null,"role":"editor"}]}}}},"responses":{"201":{"description":"The new space.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space, 2 to 10 letters or digits. It appears in addresses."},"type":{"type":"string","description":"Type of the space: `standard` for pages, blog posts, meetings and whiteboards, or `knowledgeBase` for articles in categories. Chosen at creation. New values can be added in later versions; handle unknown values.","x-extensible-enum":["standard","knowledgeBase"]},"audience":{"anyOf":[{"type":"string","description":"Who may read a knowledge base: `public` (everyone, also without signing in, once the portal exists; in Lunedo all internal users), `signedIn` (all internal users of the instance), `groups` (members of the groups that hold the reader role) or `portal` (portal accounts; in Lunedo only holders of a role). Categories and articles can narrow it with view restrictions, never widen it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["public","signedIn","groups","portal"]},{"type":"null"}],"description":"Who may read the knowledge base, or null for other spaces."},"name":{"type":"string","description":"Name of the space. Empty for a personal space that has no name of its own."},"displayName":{"type":"string","description":"Name to show: the name of the space, or for a personal space without a name of its own \"Personal space of\" and the owner's name, in the owner's language."},"description":{"type":"string","description":"Short description, up to 1000 characters."},"visibility":{"type":"string","enum":["private","organization","instance"],"description":"Who can read the space besides its holders: `private` (only holders), `organization` (every member of the organization) or `instance` (every internal user of the instance)."},"discoverable":{"type":"boolean","description":"Whether members of the organization can find the space and ask for access without reading it."},"confidential":{"type":"boolean","description":"Whether the space is confidential: only its members can read it, and administrators cannot give themselves or others access. Chosen at creation."},"oneOnOne":{"type":"boolean","description":"Whether the space holds a one-on-one."},"quarantined":{"type":"boolean","description":"Whether the space holds an import that is not accepted yet. Only the importing administrator and the reviewers can read it."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization the space belongs to, or null for a personal space."},"organizationName":{"description":"Name of the organization, or null for a personal space.","type":["string","null"]},"personal":{"type":"boolean","description":"Whether this is a personal space."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of a personal space, or null."},"ownerName":{"description":"Name of the owner of a personal space, or null.","type":["string","null"]},"overviewItemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The overview page of the space, or null for a knowledge base."},"overviewItemNumber":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the overview page in the addresses of the app, or null for a knowledge base."},"archived":{"type":"boolean","description":"Whether the space is archived. Archived spaces are read-only."},"exportEnabled":{"type":"boolean","description":"Whether pages and the space can be exported. Space administrators turn export off and on; it applies to everyone. Turning it off does not prevent copying content."},"createdAt":{"type":"string","format":"date-time","description":"When the space was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the settings of the space last changed. ISO 8601 timestamp in UTC."}},"required":["id","key","type","audience","name","displayName","description","visibility","discoverable","confidential","oneOnOne","quarantined","organizationId","organizationName","personal","ownerId","ownerName","overviewItemId","overviewItemNumber","archived","exportEnabled","createdAt","updatedAt"],"additionalProperties":false,"description":"A space."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","key":"ITOPS","type":"standard","audience":null,"name":"IT Operations","displayName":"IT Operations","description":"Runbooks and how-tos of the IT team","visibility":"organization","discoverable":false,"confidential":false,"oneOnOne":false,"quarantined":false,"organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","organizationName":"Example Inc.","personal":false,"ownerId":null,"ownerName":null,"overviewItemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a11","overviewItemNumber":1001,"archived":false,"exportEnabled":true,"createdAt":"2026-10-05T08:00:00.000Z","updatedAt":"2026-10-05T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `audienceGroupsMissing`: Choose at least one group. `invalidAudience`: Only knowledge bases have an audience. `invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid. `invalidSpaceDescription`: The space description is too long. `invalidSpaceKey`: The space key is not valid. `invalidSpaceName`: The space name is not valid. `invalidVisibility`: The space needs a visibility. `knowledgeBaseConfidential`: A knowledge base cannot be confidential. `portalAccountReaderOnly`: Portal accounts can only read.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"audienceGroupsMissing":{"value":{"type":"urn:lunedo:problem:audienceGroupsMissing","title":"Choose at least one group","status":400,"code":"audienceGroupsMissing"}},"invalidAudience":{"value":{"type":"urn:lunedo:problem:invalidAudience","title":"Only knowledge bases have an audience","status":400,"code":"invalidAudience"}},"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidSpaceDescription":{"value":{"type":"urn:lunedo:problem:invalidSpaceDescription","title":"The space description is too long","status":400,"code":"invalidSpaceDescription"}},"invalidSpaceKey":{"value":{"type":"urn:lunedo:problem:invalidSpaceKey","title":"The space key is not valid","status":400,"code":"invalidSpaceKey"}},"invalidSpaceName":{"value":{"type":"urn:lunedo:problem:invalidSpaceName","title":"The space name is not valid","status":400,"code":"invalidSpaceName"}},"invalidVisibility":{"value":{"type":"urn:lunedo:problem:invalidVisibility","title":"The space needs a visibility","status":400,"code":"invalidVisibility"}},"knowledgeBaseConfidential":{"value":{"type":"urn:lunedo:problem:knowledgeBaseConfidential","title":"A knowledge base cannot be confidential","status":400,"code":"knowledgeBaseConfidential"}},"portalAccountReaderOnly":{"value":{"type":"urn:lunedo:problem:portalAccountReaderOnly","title":"Portal accounts can only read","status":400,"code":"portalAccountReaderOnly"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`keyTaken`: The space key is taken. `privateSpaceBroadGrant`: A private space gives roles to people and groups only.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"keyTaken":{"value":{"type":"urn:lunedo:problem:keyTaken","title":"The space key is taken","status":409,"code":"keyTaken"}},"privateSpaceBroadGrant":{"value":{"type":"urn:lunedo:problem:privateSpaceBroadGrant","title":"A private space gives roles to people and groups only","status":409,"code":"privateSpaceBroadGrant"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/spaces-without-administrator":{"get":{"operationId":"organizationSpaces.withoutAdministrator","summary":"List spaces without a space admin","description":"Lists spaces of the organization in which no active account holds the space admin role, for example after the last space admin was deactivated.\n\nRequires the permission `organization.spaces.view` on the organization in `organizationId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"organization.spaces.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"Spaces without a space admin.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space, 2 to 10 letters or digits. It appears in addresses."},"type":{"type":"string","description":"Type of the space: `standard` for pages, blog posts, meetings and whiteboards, or `knowledgeBase` for articles in categories. Chosen at creation. New values can be added in later versions; handle unknown values.","x-extensible-enum":["standard","knowledgeBase"]},"audience":{"anyOf":[{"type":"string","description":"Who may read a knowledge base: `public` (everyone, also without signing in, once the portal exists; in Lunedo all internal users), `signedIn` (all internal users of the instance), `groups` (members of the groups that hold the reader role) or `portal` (portal accounts; in Lunedo only holders of a role). Categories and articles can narrow it with view restrictions, never widen it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["public","signedIn","groups","portal"]},{"type":"null"}],"description":"Who may read the knowledge base, or null for other spaces."},"name":{"type":"string","description":"Name of the space. Empty for a personal space that has no name of its own."},"displayName":{"type":"string","description":"Name to show: the name of the space, or for a personal space without a name of its own \"Personal space of\" and the owner's name, in the owner's language."},"description":{"type":"string","description":"Short description, up to 1000 characters."},"visibility":{"type":"string","enum":["private","organization","instance"],"description":"Who can read the space besides its holders: `private` (only holders), `organization` (every member of the organization) or `instance` (every internal user of the instance)."},"discoverable":{"type":"boolean","description":"Whether members of the organization can find the space and ask for access without reading it."},"confidential":{"type":"boolean","description":"Whether the space is confidential: only its members can read it, and administrators cannot give themselves or others access. Chosen at creation."},"oneOnOne":{"type":"boolean","description":"Whether the space holds a one-on-one."},"quarantined":{"type":"boolean","description":"Whether the space holds an import that is not accepted yet. Only the importing administrator and the reviewers can read it."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization the space belongs to, or null for a personal space."},"organizationName":{"description":"Name of the organization, or null for a personal space.","type":["string","null"]},"personal":{"type":"boolean","description":"Whether this is a personal space."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of a personal space, or null."},"ownerName":{"description":"Name of the owner of a personal space, or null.","type":["string","null"]},"overviewItemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The overview page of the space, or null for a knowledge base."},"overviewItemNumber":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the overview page in the addresses of the app, or null for a knowledge base."},"archived":{"type":"boolean","description":"Whether the space is archived. Archived spaces are read-only."},"exportEnabled":{"type":"boolean","description":"Whether pages and the space can be exported. Space administrators turn export off and on; it applies to everyone. Turning it off does not prevent copying content."},"createdAt":{"type":"string","format":"date-time","description":"When the space was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the settings of the space last changed. ISO 8601 timestamp in UTC."}},"required":["id","key","type","audience","name","displayName","description","visibility","discoverable","confidential","oneOnOne","quarantined","organizationId","organizationName","personal","ownerId","ownerName","overviewItemId","overviewItemNumber","archived","exportEnabled","createdAt","updatedAt"],"additionalProperties":false,"description":"A space."},"description":"Spaces, ordered by name."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"One page of results."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","key":"ITOPS","type":"standard","audience":null,"name":"IT Operations","displayName":"IT Operations","description":"Runbooks and how-tos of the IT team","visibility":"organization","discoverable":false,"confidential":false,"oneOnOne":false,"quarantined":false,"organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","organizationName":"Example Inc.","personal":false,"ownerId":null,"ownerName":null,"overviewItemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a11","overviewItemNumber":1001,"archived":false,"exportEnabled":true,"createdAt":"2026-10-05T08:00:00.000Z","updatedAt":"2026-10-05T08:00:00.000Z"}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/spaces/{spaceId}/administrator":{"post":{"operationId":"organizationSpaces.appoint","summary":"Appoint a space admin","description":"Makes a person of the organization space admin of a space that has none. Administrators cannot appoint themselves. The appointment is audited and the person is notified.\n\nRequires the permission `organization.spaces.manage` on the organization in `organizationId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"organization.spaces.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"Person of the organization who becomes space admin."}},"required":["accountId"],"additionalProperties":false,"description":"The new space admin."},"example":{"accountId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20"}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid. `selfAppointment`: Nobody can give themselves access this way.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"selfAppointment":{"value":{"type":"urn:lunedo:problem:selfAppointment","title":"Nobody can give themselves access this way","status":400,"code":"selfAppointment"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`spaceHasAdministrator`: The space has a space admin.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"spaceHasAdministrator":{"value":{"type":"urn:lunedo:problem:spaceHasAdministrator","title":"The space has a space admin","status":409,"code":"spaceHasAdministrator"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/spaces/{spaceId}/self-appointment":{"post":{"operationId":"organizationSpaces.becomeAdministrator","summary":"Become space admin of a space","description":"Gives the caller the space admin role in a space of the organization that is not personal, one-on-one or confidential. Requires a reason, which goes into the audit log; the current space admins get a notification and an e-mail with who, when and why. The role is a normal space admin role: visible in the permissions of the space and removable there. Needs a signed-in session; API tokens are refused.\n\nRequires the permission `organization.spaces.manage` on the organization in `organizationId`. Needs a signed-in session; API tokens are refused.","tags":["Spaces"],"x-lunedo-permission":{"action":"organization.spaces.manage","resource":"organization","parameter":"organizationId"},"security":[{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":1000,"description":"Why the caller needs the role, 1 to 500 characters; it goes into the audit log and to the space admins."}},"required":["reason"],"additionalProperties":false,"description":"The reason."},"example":{"reason":"The team left; the space needs a new owner for its pages"}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid. `reasonRequired`: A reason is required.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"reasonRequired":{"value":{"type":"urn:lunedo:problem:reasonRequired","title":"A reason is required","status":400,"code":"reasonRequired"}}}}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `reauthenticationRequired`: Confirm your identity first. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"reauthenticationRequired":{"value":{"type":"urn:lunedo:problem:reauthenticationRequired","title":"Confirm your identity first","status":403,"code":"reauthenticationRequired"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`alreadyAdministrator`: You are already space admin of this space.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"alreadyAdministrator":{"value":{"type":"urn:lunedo:problem:alreadyAdministrator","title":"You are already space admin of this space","status":409,"code":"alreadyAdministrator"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/storage":{"get":{"operationId":"accessRequests.organizationStorage","summary":"Get the storage used by an organization","description":"Sums the attachments of all spaces of the organization, with every stored version.\n\nRequires the permission `organization.spaces.view` on the organization in `organizationId`.","tags":["Access"],"x-lunedo-permission":{"action":"organization.spaces.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The storage.","content":{"application/json":{"schema":{"type":"object","properties":{"bytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Bytes used by all versions of all attachments."},"files":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of stored files."}},"required":["bytes","files"],"additionalProperties":false,"description":"Storage used by attachments."},"example":{"bytes":1073741824,"files":1200}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/template-imports":{"post":{"operationId":"templateFiles.organizationImport","summary":"Upload a template file for import into the organization","description":"Checks a template file and returns a preview, like for spaces; nothing is saved yet.\n\nRequires the permission `organization.templates.manage` on the organization in `organizationId`.","tags":["Templates"],"x-lunedo-permission":{"action":"organization.templates.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"name","in":"query","required":true,"description":"Name of the uploaded file. Paths and control characters are removed.","schema":{"type":"string","minLength":1,"maxLength":1020}}],"requestBody":{"required":true,"description":"The template file.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"201":{"description":"The preview.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the preview; confirm or discard it with this ID."},"fileName":{"type":"string","description":"Name of the uploaded file."},"templates":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Position in the file, counted from 0."},"name":{"type":"string","description":"Name of the template, or `#n` when the file gives none."},"description":{"type":"string","description":"Short description."},"category":{"anyOf":[{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"]},{"type":"null"}],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"language":{"anyOf":[{"type":"string","enum":["en","de"]},{"type":"null"}],"description":"Language the file states, or null."},"title":{"type":"string","description":"Title pattern of new pages."},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Input fields."},"series":{"anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","description":"How often. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"Weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"Default rhythm."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Default duration in minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false,"description":"Defaults of a series template."},{"type":"null"}],"description":"Series defaults, or null."},"document":{"anyOf":[{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},{"type":"null"}],"description":"Content as it will be saved, or null if it is not valid."},"files":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the file; the preview content refers to it."},"name":{"type":"string","description":"File name."},"mediaType":{"type":"string","description":"Media type."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size in bytes after the safety checks."}},"required":["id","name","mediaType","size"],"additionalProperties":false,"description":"A file of the template."},"description":"Files the content uses."},"removed":{"type":"object","propertyNames":{"type":"string","enum":["pageLink","mention","include","diagramReference","whiteboard","templateButton","report","roadmap","person","comment","meetingTopic","file","unsupportedMacro"]},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"What is removed because it cannot work in another instance, by kind: `pageLink` (links to pages and spaces), `mention`, `include`, `diagramReference`, `whiteboard`, `templateButton`, `report`, `roadmap`, `person`, `comment`, `meetingTopic`, `file` (files that are not part of the template or not images) and `unsupportedMacro`."},"blockedEmbeds":{"type":"array","items":{"type":"string","description":"Address of an embed."},"description":"Embeds this instance does not allow; they stay in the content and show as links."},"problems":{"type":"array","items":{"type":"object","properties":{"place":{"description":"Where, such as `field 3` or `content`.","type":["string","null"]},"message":{"type":"string","description":"Explanation naming the template and the place."}},"required":["place","message"],"additionalProperties":false,"description":"A problem."},"description":"Why the template cannot be imported; empty when it can."},"valid":{"type":"boolean","description":"Whether the template can be imported."},"conflict":{"anyOf":[{"type":"object","properties":{"templateId":{"type":"string","format":"uuid","description":"The template with the same name at this level."},"suggestedName":{"type":"string","description":"A new name to use instead, in the caller's language."}},"required":["templateId","suggestedName"],"additionalProperties":false},{"type":"null"}],"description":"A template with the same name at this level, or null."}},"required":["index","name","description","category","language","title","fields","series","document","files","removed","blockedEmbeds","problems","valid","conflict"],"additionalProperties":false,"description":"A template of the uploaded file."},"description":"The templates of the file."},"expiresAt":{"type":"string","format":"date-time","description":"When the preview is discarded."}},"required":["id","fileName","templates","expiresAt"],"additionalProperties":false,"description":"What an import will create. Nothing is saved before it is confirmed."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5aa0","fileName":"change-request.lunedo-template.zip","templates":[{"index":0,"name":"Change request","description":"Planned change with risk and rollback","category":"operations","language":"en","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"series":null,"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"files":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a91","name":"rollout.png","mediaType":"image/png","size":48213}],"removed":{},"blockedEmbeds":[],"problems":[],"valid":true,"conflict":{"templateId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","suggestedName":"Change request (imported)"}}],"expiresAt":"2026-10-18T20:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidTemplateFile`: The file is not a valid Lunedo template file. `nestedTemplateArchive`: The archive contains another archive. `newerTemplateFormat`: The template file was written by a newer Lunedo. `templateArchiveCompression`: A file in the archive is compressed too strongly. `tooManyTemplateFiles`: The archive holds more files than allowed. `tooManyTemplates`: The file holds more templates than allowed. `unexpectedTemplateEntry`: The archive contains an unexpected file. `unsafeTemplateArchive`: The archive contains unsafe entries.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidTemplateFile":{"value":{"type":"urn:lunedo:problem:invalidTemplateFile","title":"The file is not a valid Lunedo template file","status":400,"code":"invalidTemplateFile"}},"nestedTemplateArchive":{"value":{"type":"urn:lunedo:problem:nestedTemplateArchive","title":"The archive contains another archive","status":400,"code":"nestedTemplateArchive"}},"newerTemplateFormat":{"value":{"type":"urn:lunedo:problem:newerTemplateFormat","title":"The template file was written by a newer Lunedo","status":400,"code":"newerTemplateFormat"}},"templateArchiveCompression":{"value":{"type":"urn:lunedo:problem:templateArchiveCompression","title":"A file in the archive is compressed too strongly","status":400,"code":"templateArchiveCompression"}},"tooManyTemplateFiles":{"value":{"type":"urn:lunedo:problem:tooManyTemplateFiles","title":"The archive holds more files than allowed","status":400,"code":"tooManyTemplateFiles"}},"tooManyTemplates":{"value":{"type":"urn:lunedo:problem:tooManyTemplates","title":"The file holds more templates than allowed","status":400,"code":"tooManyTemplates"}},"unexpectedTemplateEntry":{"value":{"type":"urn:lunedo:problem:unexpectedTemplateEntry","title":"The archive contains an unexpected file","status":400,"code":"unexpectedTemplateEntry"}},"unsafeTemplateArchive":{"value":{"type":"urn:lunedo:problem:unsafeTemplateArchive","title":"The archive contains unsafe entries","status":400,"code":"unsafeTemplateArchive"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"408":{"description":"`uploadTimeout`: The upload took too long.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"uploadTimeout":{"value":{"type":"urn:lunedo:problem:uploadTimeout","title":"The upload took too long","status":408,"code":"uploadTimeout"}}}}}},"413":{"description":"`fileTooLarge`: The file is larger than allowed. `templateArchiveTooLarge`: The archive unpacks to more than allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"fileTooLarge":{"value":{"type":"urn:lunedo:problem:fileTooLarge","title":"The file is larger than allowed","status":413,"code":"fileTooLarge"}},"templateArchiveTooLarge":{"value":{"type":"urn:lunedo:problem:templateArchiveTooLarge","title":"The archive unpacks to more than allowed","status":413,"code":"templateArchiveTooLarge"}}}}}},"415":{"description":"`unsupportedMediaType`: The request body has an unsupported type.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unsupportedMediaType":{"value":{"type":"urn:lunedo:problem:unsupportedMediaType","title":"The request body has an unsupported type","status":415,"code":"unsupportedMediaType"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`busy`: The server is busy. `maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"busy":{"value":{"type":"urn:lunedo:problem:busy","title":"The server is busy","status":503,"code":"busy"}},"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}},"507":{"description":"`storageFull`: Storage is almost full.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"storageFull":{"value":{"type":"urn:lunedo:problem:storageFull","title":"Storage is almost full","status":507,"code":"storageFull"}}}}}}}}},"/api/v1/organizations/{organizationId}/template-imports/{importId}":{"delete":{"operationId":"templateFiles.organizationDiscard","summary":"Discard an organization import preview","description":"Discards your preview and its files.\n\nRequires the permission `organization.templates.manage` on the organization in `organizationId`.","tags":["Templates"],"x-lunedo-permission":{"action":"organization.templates.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"importId","in":"path","required":true,"description":"ID of the import preview.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `templateImportNotFound`: The import preview does not exist anymore.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"templateImportNotFound":{"value":{"type":"urn:lunedo:problem:templateImportNotFound","title":"The import preview does not exist anymore","status":404,"code":"templateImportNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/template-imports/{importId}/confirm":{"post":{"operationId":"templateFiles.organizationConfirm","summary":"Confirm an import into the organization","description":"Imports the templates of your preview as organization templates, with the same decisions as for spaces.\n\nRequires the permission `organization.templates.manage` on the organization in `organizationId`.","tags":["Templates"],"x-lunedo-permission":{"action":"organization.templates.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"importId","in":"path","required":true,"description":"ID of the import preview.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"decisions":{"default":[],"description":"Decisions per template. Templates without a decision are created under their own name.","maxItems":50,"type":"array","items":{"type":"object","properties":{"index":{"type":"integer","minimum":0,"maximum":50,"description":"Position in the file."},"action":{"type":"string","enum":["create","replace","skip"],"description":"`create` a new template, `replace` the template with the same name (it keeps its ID), or `skip` it."},"name":{"description":"Name of a new template; default: the name in the file.","type":"string","maxLength":200}},"required":["index","action"],"additionalProperties":false,"description":"What to do with one template."}},"skipInvalid":{"default":false,"description":"Import the valid templates when others in the file are not valid. Without it, nothing is imported.","type":"boolean"}},"additionalProperties":false,"description":"Confirms an import preview."},"example":{"decisions":[{"index":0,"action":"replace"}]}}}},"responses":{"200":{"description":"The result.","content":{"application/json":{"schema":{"type":"object","properties":{"created":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"ID of the template. Built-in templates have IDs starting with `builtin:`."},"level":{"type":"string","enum":["builtIn","instance","organization","space"],"description":"Where the template comes from: built in, or from the instance, the organization or the space."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization of an organization template, or null."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space of a space template, or null."},"name":{"type":"string","description":"Name."},"description":{"type":"string","description":"Short description."},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","description":"Title of new pages; `{key}` inserts the value of an input field."},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","description":"How often. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"Weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"Default rhythm."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Default duration in minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false,"description":"Defaults of a series template."},{"type":"null"}],"description":"For a series template: defaults for rhythm and duration of new meeting series; otherwise null."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Article type of articles created from a template of a knowledge base, or null."},"updatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the template last changed, or null for built-in templates. ISO 8601 timestamp in UTC."}},"required":["id","level","organizationId","spaceId","name","description","category","title","fields","document","series","articleType","updatedAt"],"additionalProperties":false,"description":"A page template."},"description":"Templates created."},"replaced":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"ID of the template. Built-in templates have IDs starting with `builtin:`."},"level":{"type":"string","enum":["builtIn","instance","organization","space"],"description":"Where the template comes from: built in, or from the instance, the organization or the space."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization of an organization template, or null."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space of a space template, or null."},"name":{"type":"string","description":"Name."},"description":{"type":"string","description":"Short description."},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","description":"Title of new pages; `{key}` inserts the value of an input field."},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","description":"How often. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"Weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"Default rhythm."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Default duration in minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false,"description":"Defaults of a series template."},{"type":"null"}],"description":"For a series template: defaults for rhythm and duration of new meeting series; otherwise null."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Article type of articles created from a template of a knowledge base, or null."},"updatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the template last changed, or null for built-in templates. ISO 8601 timestamp in UTC."}},"required":["id","level","organizationId","spaceId","name","description","category","title","fields","document","series","articleType","updatedAt"],"additionalProperties":false,"description":"A page template."},"description":"Templates replaced; they keep their IDs."},"skipped":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Templates not imported."}},"required":["created","replaced","skipped"],"additionalProperties":false,"description":"The result of an import."},"example":{"created":[],"replaced":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","level":"space","organizationId":null,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","name":"Change request","description":"Planned change with risk and rollback","category":"operations","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"series":null,"articleType":null,"updatedAt":"2026-10-05T08:00:00.000Z"}],"skipped":0}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidTemplateName`: The template name is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidTemplateName":{"value":{"type":"urn:lunedo:problem:invalidTemplateName","title":"The template name is not valid","status":400,"code":"invalidTemplateName"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `templateImportNotFound`: The import preview does not exist anymore. `templateNotFound`: The template does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"templateImportNotFound":{"value":{"type":"urn:lunedo:problem:templateImportNotFound","title":"The import preview does not exist anymore","status":404,"code":"templateImportNotFound"}},"templateNotFound":{"value":{"type":"urn:lunedo:problem:templateNotFound","title":"The template does not exist","status":404,"code":"templateNotFound"}}}}}},"409":{"description":"`invalidTemplatesInFile`: Some templates in the file are not valid. `templateNameTaken`: A template with this name exists already.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidTemplatesInFile":{"value":{"type":"urn:lunedo:problem:invalidTemplatesInFile","title":"Some templates in the file are not valid","status":409,"code":"invalidTemplatesInFile"}},"templateNameTaken":{"value":{"type":"urn:lunedo:problem:templateNameTaken","title":"A template with this name exists already","status":409,"code":"templateNameTaken"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}},"507":{"description":"`storageFull`: Storage is almost full.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"storageFull":{"value":{"type":"urn:lunedo:problem:storageFull","title":"Storage is almost full","status":507,"code":"storageFull"}}}}}}}}},"/api/v1/organizations/{organizationId}/template-imports/{importId}/files/{fileId}/content":{"get":{"operationId":"templateFiles.organizationImportFile","summary":"Download a file of an organization import preview","description":"Sends a checked file of your import preview.\n\nRequires the permission `organization.templates.manage` on the organization in `organizationId`.","tags":["Templates"],"x-lunedo-permission":{"action":"organization.templates.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"importId","in":"path","required":true,"description":"ID of the import preview.","schema":{"type":"string","format":"uuid"}},{"name":"fileId","in":"path","required":true,"description":"ID of the file.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The file. Sent with `Content-Security-Policy: sandbox` and `X-Content-Type-Options: nosniff`; ranges are supported.","content":{"image/png":{"schema":{"type":"string"},"example":""},"image/jpeg":{"schema":{"type":"string"},"example":""},"image/gif":{"schema":{"type":"string"},"example":""},"image/webp":{"schema":{"type":"string"},"example":""},"image/svg+xml":{"schema":{"type":"string"},"example":""},"*/*":{"schema":{"type":"string"},"example":""}}},"206":{"description":"Part of the file, for a request with a `Range` header.","content":{"image/png":{"schema":{"type":"string"},"example":""},"image/jpeg":{"schema":{"type":"string"},"example":""},"image/gif":{"schema":{"type":"string"},"example":""},"image/webp":{"schema":{"type":"string"},"example":""},"image/svg+xml":{"schema":{"type":"string"},"example":""},"*/*":{"schema":{"type":"string"},"example":""}}},"304":{"description":"Not modified: the file matches the `If-None-Match` header."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `templateImportNotFound`: The import preview does not exist anymore.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"templateImportNotFound":{"value":{"type":"urn:lunedo:problem:templateImportNotFound","title":"The import preview does not exist anymore","status":404,"code":"templateImportNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/templates":{"get":{"operationId":"templates.organizationTemplates","summary":"List the templates of an organization","description":"Lists the templates available in all spaces of the organization.\n\nRequires the permission `organization.templates.manage` on the organization in `organizationId`.","tags":["Templates"],"x-lunedo-permission":{"action":"organization.templates.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Templates.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"ID of the template. Built-in templates have IDs starting with `builtin:`."},"level":{"type":"string","enum":["builtIn","instance","organization","space"],"description":"Where the template comes from: built in, or from the instance, the organization or the space."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization of an organization template, or null."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space of a space template, or null."},"name":{"type":"string","description":"Name."},"description":{"type":"string","description":"Short description."},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","description":"Title of new pages; `{key}` inserts the value of an input field."},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","description":"How often. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"Weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"Default rhythm."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Default duration in minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false,"description":"Defaults of a series template."},{"type":"null"}],"description":"For a series template: defaults for rhythm and duration of new meeting series; otherwise null."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Article type of articles created from a template of a knowledge base, or null."},"updatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the template last changed, or null for built-in templates. ISO 8601 timestamp in UTC."}},"required":["id","level","organizationId","spaceId","name","description","category","title","fields","document","series","articleType","updatedAt"],"additionalProperties":false,"description":"A page template."},"description":"Templates."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","level":"organization","organizationId":null,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","name":"Change request","description":"Planned change with risk and rollback","category":"operations","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"series":null,"articleType":null,"updatedAt":"2026-10-05T08:00:00.000Z"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"templates.createOrganizationTemplate","summary":"Create an organization template","description":"Creates a template for all spaces of the organization.\n\nRequires the permission `organization.templates.manage` on the organization in `organizationId`.","tags":["Templates"],"x-lunedo-permission":{"action":"organization.templates.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"description":"Name, 1 to 100 characters."},"description":{"default":"","description":"Short description, up to 300 characters.","type":"string","maxLength":300},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","maxLength":255,"description":"Title of new pages, 1 to 255 characters."},"fields":{"maxItems":20,"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Up to 20 input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"description":"Makes the template a series template with these defaults; null or left out for a page template.","anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","enum":["none","daily","weekly","monthly","yearly"],"description":"`none` for no fixed rhythm, otherwise how often the meetings repeat."},"interval":{"default":1,"description":"Every how many days, weeks, months or years. 2 weekly is every two weeks, 3 monthly is quarterly.","type":"integer","minimum":1,"maximum":52},"weekdays":{"description":"For `weekly`: the weekdays of the meetings, at least one.","maxItems":7,"type":"array","items":{"type":"string","enum":["MO","TU","WE","TH","FR","SA","SU"],"description":"Weekday as in iCalendar: `MO` to `SU`."}},"monthDay":{"description":"For `monthly` by date: the day of the month.","type":"integer","minimum":1,"maximum":31},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"For `monthly` by weekday: the weekday, for example `TU`.","type":"string","enum":["MO","TU","WE","TH","FR","SA","SU"]}},"required":["frequency"],"additionalProperties":false,"description":"The rhythm of a series, as the interface offers it."},"durationMinutes":{"type":"integer","minimum":5,"maximum":1440,"description":"Minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false},{"type":"null"}]},"articleType":{"description":"Article type of articles created from the template. Only templates of a knowledge base have one; left out, a change keeps the current type.","anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}]}},"required":["name","category","title","fields","document"],"additionalProperties":false,"description":"A template."},"example":{"name":"Change request","description":"Planned change with risk and rollback","category":"operations","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]}}}}},"responses":{"201":{"description":"The template.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"ID of the template. Built-in templates have IDs starting with `builtin:`."},"level":{"type":"string","enum":["builtIn","instance","organization","space"],"description":"Where the template comes from: built in, or from the instance, the organization or the space."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization of an organization template, or null."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space of a space template, or null."},"name":{"type":"string","description":"Name."},"description":{"type":"string","description":"Short description."},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","description":"Title of new pages; `{key}` inserts the value of an input field."},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","description":"How often. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"Weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"Default rhythm."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Default duration in minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false,"description":"Defaults of a series template."},{"type":"null"}],"description":"For a series template: defaults for rhythm and duration of new meeting series; otherwise null."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Article type of articles created from a template of a knowledge base, or null."},"updatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the template last changed, or null for built-in templates. ISO 8601 timestamp in UTC."}},"required":["id","level","organizationId","spaceId","name","description","category","title","fields","document","series","articleType","updatedAt"],"additionalProperties":false,"description":"A page template."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","level":"organization","organizationId":null,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","name":"Change request","description":"Planned change with risk and rollback","category":"operations","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"series":null,"articleType":null,"updatedAt":"2026-10-05T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidDescription`: The description is too long. `invalidDocument`: The document does not match the editor schema. `invalidInput`: The request is not valid. `invalidTemplateFields`: The input fields of the template are not valid. `invalidTemplateName`: The template name is not valid. `invalidTitle`: The title is not valid. `unknownTemplateField`: The template uses an input field that does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidDescription":{"value":{"type":"urn:lunedo:problem:invalidDescription","title":"The description is too long","status":400,"code":"invalidDescription"}},"invalidDocument":{"value":{"type":"urn:lunedo:problem:invalidDocument","title":"The document does not match the editor schema","status":400,"code":"invalidDocument"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidTemplateFields":{"value":{"type":"urn:lunedo:problem:invalidTemplateFields","title":"The input fields of the template are not valid","status":400,"code":"invalidTemplateFields"}},"invalidTemplateName":{"value":{"type":"urn:lunedo:problem:invalidTemplateName","title":"The template name is not valid","status":400,"code":"invalidTemplateName"}},"invalidTitle":{"value":{"type":"urn:lunedo:problem:invalidTitle","title":"The title is not valid","status":400,"code":"invalidTitle"}},"unknownTemplateField":{"value":{"type":"urn:lunedo:problem:unknownTemplateField","title":"The template uses an input field that does not exist","status":400,"code":"unknownTemplateField"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/templates/{templateId}":{"delete":{"operationId":"templates.deleteOrganizationTemplate","summary":"Delete an organization template","description":"Deletes a template of the organization. Pages created from it stay.\n\nRequires the permission `organization.templates.manage` on the organization in `organizationId`.","tags":["Templates"],"x-lunedo-permission":{"action":"organization.templates.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"templateId","in":"path","required":true,"description":"ID of the template.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"put":{"operationId":"templates.updateOrganizationTemplate","summary":"Change an organization template","description":"Changes a template of the organization. Pages created from it before stay as they are.\n\nRequires the permission `organization.templates.manage` on the organization in `organizationId`.","tags":["Templates"],"x-lunedo-permission":{"action":"organization.templates.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"templateId","in":"path","required":true,"description":"ID of the template.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"description":"Name, 1 to 100 characters."},"description":{"default":"","description":"Short description, up to 300 characters.","type":"string","maxLength":300},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","maxLength":255,"description":"Title of new pages, 1 to 255 characters."},"fields":{"maxItems":20,"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Up to 20 input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"description":"Makes the template a series template with these defaults; null or left out for a page template.","anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","enum":["none","daily","weekly","monthly","yearly"],"description":"`none` for no fixed rhythm, otherwise how often the meetings repeat."},"interval":{"default":1,"description":"Every how many days, weeks, months or years. 2 weekly is every two weeks, 3 monthly is quarterly.","type":"integer","minimum":1,"maximum":52},"weekdays":{"description":"For `weekly`: the weekdays of the meetings, at least one.","maxItems":7,"type":"array","items":{"type":"string","enum":["MO","TU","WE","TH","FR","SA","SU"],"description":"Weekday as in iCalendar: `MO` to `SU`."}},"monthDay":{"description":"For `monthly` by date: the day of the month.","type":"integer","minimum":1,"maximum":31},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"For `monthly` by weekday: the weekday, for example `TU`.","type":"string","enum":["MO","TU","WE","TH","FR","SA","SU"]}},"required":["frequency"],"additionalProperties":false,"description":"The rhythm of a series, as the interface offers it."},"durationMinutes":{"type":"integer","minimum":5,"maximum":1440,"description":"Minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false},{"type":"null"}]},"articleType":{"description":"Article type of articles created from the template. Only templates of a knowledge base have one; left out, a change keeps the current type.","anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}]}},"required":["name","category","title","fields","document"],"additionalProperties":false,"description":"A template."},"example":{"name":"Change request","description":"Planned change with risk and rollback","category":"operations","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]}}}}},"responses":{"200":{"description":"The template.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"ID of the template. Built-in templates have IDs starting with `builtin:`."},"level":{"type":"string","enum":["builtIn","instance","organization","space"],"description":"Where the template comes from: built in, or from the instance, the organization or the space."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization of an organization template, or null."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space of a space template, or null."},"name":{"type":"string","description":"Name."},"description":{"type":"string","description":"Short description."},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","description":"Title of new pages; `{key}` inserts the value of an input field."},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","description":"How often. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"Weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"Default rhythm."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Default duration in minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false,"description":"Defaults of a series template."},{"type":"null"}],"description":"For a series template: defaults for rhythm and duration of new meeting series; otherwise null."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Article type of articles created from a template of a knowledge base, or null."},"updatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the template last changed, or null for built-in templates. ISO 8601 timestamp in UTC."}},"required":["id","level","organizationId","spaceId","name","description","category","title","fields","document","series","articleType","updatedAt"],"additionalProperties":false,"description":"A page template."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","level":"organization","organizationId":null,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","name":"Change request","description":"Planned change with risk and rollback","category":"operations","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"series":null,"articleType":null,"updatedAt":"2026-10-05T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidDescription`: The description is too long. `invalidDocument`: The document does not match the editor schema. `invalidInput`: The request is not valid. `invalidTemplateFields`: The input fields of the template are not valid. `invalidTemplateName`: The template name is not valid. `invalidTitle`: The title is not valid. `unknownTemplateField`: The template uses an input field that does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidDescription":{"value":{"type":"urn:lunedo:problem:invalidDescription","title":"The description is too long","status":400,"code":"invalidDescription"}},"invalidDocument":{"value":{"type":"urn:lunedo:problem:invalidDocument","title":"The document does not match the editor schema","status":400,"code":"invalidDocument"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidTemplateFields":{"value":{"type":"urn:lunedo:problem:invalidTemplateFields","title":"The input fields of the template are not valid","status":400,"code":"invalidTemplateFields"}},"invalidTemplateName":{"value":{"type":"urn:lunedo:problem:invalidTemplateName","title":"The template name is not valid","status":400,"code":"invalidTemplateName"}},"invalidTitle":{"value":{"type":"urn:lunedo:problem:invalidTitle","title":"The title is not valid","status":400,"code":"invalidTitle"}},"unknownTemplateField":{"value":{"type":"urn:lunedo:problem:unknownTemplateField","title":"The template uses an input field that does not exist","status":400,"code":"unknownTemplateField"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/templates/{templateId}/files":{"post":{"operationId":"templateFiles.organizationUpload","summary":"Add an image to an organization template","description":"Stores an image for the template, like for space templates: PNG, JPEG, GIF, WebP or SVG up to 5 MB.\n\nRequires the permission `organization.templates.manage` on the organization in `organizationId`.","tags":["Templates"],"x-lunedo-permission":{"action":"organization.templates.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"templateId","in":"path","required":true,"description":"ID of the template.","schema":{"type":"string","format":"uuid"}},{"name":"name","in":"query","required":true,"description":"Name of the uploaded file. Paths and control characters are removed.","schema":{"type":"string","minLength":1,"maxLength":1020}}],"requestBody":{"required":true,"description":"The bytes of the image.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"201":{"description":"The file.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the file. Content of the template refers to it, for example as `attachmentId` of an image."},"templateId":{"type":"string","format":"uuid","description":"ID of the template."},"name":{"type":"string","description":"File name."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size in bytes."},"contentType":{"type":"string","description":"Media type, decided from the content."}},"required":["id","templateId","name","size","contentType"],"additionalProperties":false,"description":"A file of a template."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a91","templateId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","name":"rollout.png","size":48213,"contentType":"image/png"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidFileName`: The file name is not valid. `invalidInput`: The request is not valid. `unsupportedTemplateFile`: Templates hold PNG, JPEG, GIF, WebP and SVG images only.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidFileName":{"value":{"type":"urn:lunedo:problem:invalidFileName","title":"The file name is not valid","status":400,"code":"invalidFileName"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"unsupportedTemplateFile":{"value":{"type":"urn:lunedo:problem:unsupportedTemplateFile","title":"Templates hold PNG, JPEG, GIF, WebP and SVG images only","status":400,"code":"unsupportedTemplateFile"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"408":{"description":"`uploadTimeout`: The upload took too long.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"uploadTimeout":{"value":{"type":"urn:lunedo:problem:uploadTimeout","title":"The upload took too long","status":408,"code":"uploadTimeout"}}}}}},"413":{"description":"`fileTooLarge`: The file is larger than allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"fileTooLarge":{"value":{"type":"urn:lunedo:problem:fileTooLarge","title":"The file is larger than allowed","status":413,"code":"fileTooLarge"}}}}}},"415":{"description":"`unsupportedMediaType`: The request body has an unsupported type.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unsupportedMediaType":{"value":{"type":"urn:lunedo:problem:unsupportedMediaType","title":"The request body has an unsupported type","status":415,"code":"unsupportedMediaType"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`busy`: The server is busy. `maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"busy":{"value":{"type":"urn:lunedo:problem:busy","title":"The server is busy","status":503,"code":"busy"}},"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}},"507":{"description":"`storageFull`: Storage is almost full.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"storageFull":{"value":{"type":"urn:lunedo:problem:storageFull","title":"Storage is almost full","status":507,"code":"storageFull"}}}}}}}}},"/api/v1/organizations/{organizationId}/templates/{templateId}/files/{fileId}/content":{"get":{"operationId":"templateFiles.organizationTemplateFile","summary":"Download a file of an organization template","description":"Sends a file of a template of the organization.\n\nRequires the permission `organization.templates.manage` on the organization in `organizationId`.","tags":["Templates"],"x-lunedo-permission":{"action":"organization.templates.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"templateId","in":"path","required":true,"description":"ID of the template.","schema":{"type":"string","format":"uuid"}},{"name":"fileId","in":"path","required":true,"description":"ID of the file.","schema":{"type":"string","format":"uuid"}},{"name":"size","in":"query","required":false,"description":"Size of an image. `display` sends a version whose longest edge is at most 2048 pixels, `preview` one of at most 400 pixels, both as WebP without metadata. The original is sent while no such version exists, for images that are already small enough, and for every other type. Images above 100 megapixels get no smaller version and answer `imageTooLarge`.","schema":{"default":"original","type":"string","enum":["original","display","preview"]}}],"responses":{"200":{"description":"The file. Sent with `Content-Security-Policy: sandbox` and `X-Content-Type-Options: nosniff`; ranges are supported.","content":{"image/png":{"schema":{"type":"string"},"example":""},"image/jpeg":{"schema":{"type":"string"},"example":""},"image/gif":{"schema":{"type":"string"},"example":""},"image/webp":{"schema":{"type":"string"},"example":""},"image/svg+xml":{"schema":{"type":"string"},"example":""},"*/*":{"schema":{"type":"string"},"example":""}}},"206":{"description":"Part of the file, for a request with a `Range` header.","content":{"image/png":{"schema":{"type":"string"},"example":""},"image/jpeg":{"schema":{"type":"string"},"example":""},"image/gif":{"schema":{"type":"string"},"example":""},"image/webp":{"schema":{"type":"string"},"example":""},"image/svg+xml":{"schema":{"type":"string"},"example":""},"*/*":{"schema":{"type":"string"},"example":""}}},"304":{"description":"Not modified: the file matches the `If-None-Match` header."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`imageTooLarge`: The image is too large for a smaller version.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"imageTooLarge":{"value":{"type":"urn:lunedo:problem:imageTooLarge","title":"The image is too large for a smaller version","status":409,"code":"imageTooLarge"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/templates/built-in":{"get":{"operationId":"templates.builtInTemplates","summary":"List the built-in templates","description":"Lists the templates that ship with Lunedo, in the language of the caller. They cannot be changed; duplicate one to adapt it.\n\nRequires the permission `organization.templates.manage` on the organization in `organizationId`.","tags":["Templates"],"x-lunedo-permission":{"action":"organization.templates.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Built-in templates.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"ID of the template. Built-in templates have IDs starting with `builtin:`."},"level":{"type":"string","enum":["builtIn","instance","organization","space"],"description":"Where the template comes from: built in, or from the instance, the organization or the space."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization of an organization template, or null."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space of a space template, or null."},"name":{"type":"string","description":"Name."},"description":{"type":"string","description":"Short description."},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","description":"Title of new pages; `{key}` inserts the value of an input field."},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","description":"How often. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"Weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"Default rhythm."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Default duration in minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false,"description":"Defaults of a series template."},{"type":"null"}],"description":"For a series template: defaults for rhythm and duration of new meeting series; otherwise null."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Article type of articles created from a template of a knowledge base, or null."},"updatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the template last changed, or null for built-in templates. ISO 8601 timestamp in UTC."}},"required":["id","level","organizationId","spaceId","name","description","category","title","fields","document","series","articleType","updatedAt"],"additionalProperties":false,"description":"A page template."},"description":"Templates."},"example":[{"id":"builtin:team-meeting","level":"builtIn","organizationId":null,"spaceId":null,"name":"Change request","description":"Planned change with risk and rollback","category":"meetings","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"series":null,"articleType":null,"updatedAt":null}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/templates/export":{"post":{"operationId":"templateFiles.organizationExport","summary":"Export organization templates","description":"Sends the chosen templates of the organization as a template file, cleaned like space templates.\n\nRequires the permission `organization.templates.manage` on the organization in `organizationId`.","tags":["Templates"],"x-lunedo-permission":{"action":"organization.templates.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"templateIds":{"default":null,"description":"The templates to export; null for all of this level, at most 50.","anyOf":[{"minItems":1,"maxItems":50,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a template."}},{"type":"null"}]}},"additionalProperties":false,"description":"Which templates to export."},"example":{"templateIds":null}}}},"responses":{"200":{"description":"A template file: JSON for templates without files, otherwise a ZIP archive with `template.json` and the files under `files/`.","content":{"application/json":{"schema":{"type":"string"},"example":"{\n  \"format\": \"lunedo-template\",\n  \"formatVersion\": 1\n}\n"},"application/zip":{"schema":{"type":"string"},"example":"{\n  \"format\": \"lunedo-template\",\n  \"formatVersion\": 1\n}\n"}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `noTemplates`: There are no templates to export. `templateExportTooLarge`: The export would be larger than allowed. `tooManyTemplates`: The file holds more templates than allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"noTemplates":{"value":{"type":"urn:lunedo:problem:noTemplates","title":"There are no templates to export","status":400,"code":"noTemplates"}},"templateExportTooLarge":{"value":{"type":"urn:lunedo:problem:templateExportTooLarge","title":"The export would be larger than allowed","status":400,"code":"templateExportTooLarge"}},"tooManyTemplates":{"value":{"type":"urn:lunedo:problem:tooManyTemplates","title":"The file holds more templates than allowed","status":400,"code":"tooManyTemplates"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `templateNotFound`: The template does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"templateNotFound":{"value":{"type":"urn:lunedo:problem:templateNotFound","title":"The template does not exist","status":404,"code":"templateNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/templates/export-summary":{"post":{"operationId":"templateFiles.organizationExportSummary","summary":"Check an export of organization templates","description":"Tells per template what an export removes, before anything is downloaded.\n\nRequires the permission `organization.templates.manage` on the organization in `organizationId`.","tags":["Templates"],"x-lunedo-permission":{"action":"organization.templates.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"templateIds":{"default":null,"description":"The templates to export; null for all of this level, at most 50.","anyOf":[{"minItems":1,"maxItems":50,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a template."}},{"type":"null"}]}},"additionalProperties":false,"description":"Which templates to export."},"example":{"templateIds":null}}}},"responses":{"200":{"description":"What the export contains.","content":{"application/json":{"schema":{"type":"object","properties":{"templates":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the template."},"files":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of files in the export."},"removed":{"type":"object","propertyNames":{"type":"string","enum":["pageLink","mention","include","diagramReference","whiteboard","templateButton","report","roadmap","person","comment","meetingTopic","file","unsupportedMacro"]},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"What is removed because it cannot work in another instance, by kind: `pageLink` (links to pages and spaces), `mention`, `include`, `diagramReference`, `whiteboard`, `templateButton`, `report`, `roadmap`, `person`, `comment`, `meetingTopic`, `file` (files that are not part of the template or not images) and `unsupportedMacro`."}},"required":["name","files","removed"],"additionalProperties":false,"description":"A template of the export."},"description":"The templates in the order of the file."}},"required":["templates"],"additionalProperties":false,"description":"What an export will contain."},"example":{"templates":[{"name":"Change request","files":1,"removed":{"pageLink":2,"mention":1}}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `templateNotFound`: The template does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"templateNotFound":{"value":{"type":"urn:lunedo:problem:templateNotFound","title":"The template does not exist","status":404,"code":"templateNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/trash":{"get":{"operationId":"trash.organizationTrash","summary":"List deleted content of an organization","description":"Lists all trash entries of the organization's spaces, both stages, and deleted spaces. Only organization administrators can restore entries of the second stage. Confidential spaces are left out.\n\nRequires the permission `organization.trash.manage` on the organization in `organizationId`.","tags":["Trash"],"x-lunedo-permission":{"action":"organization.trash.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Trash entries.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the trash entry."},"spaceId":{"type":"string","format":"uuid","description":"Space of the entry."},"spaceKey":{"type":"string","description":"Key of the space."},"spaceName":{"type":"string","description":"Name of the space."},"kind":{"type":"string","enum":["items","space"],"description":"`items` for deleted pages, folders or links, `space` for a deleted space."},"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The deleted item, or null for a space."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the deleted item in the addresses of the app, or null for a space."},"itemKind":{"anyOf":[{"type":"string","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},{"type":"null"}],"description":"Kind of the deleted item, or null for a space. New values can be added in later versions; handle unknown values."},"title":{"type":"string","description":"Title of the deleted item, or name of the space."},"descendants":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of descendants deleted with the item."},"stage":{"anyOf":[{"type":"number","const":1},{"type":"number","const":2}],"description":"1 while the entry is in the space trash, 2 after that period or after the trash was emptied; then only organization administrators can restore it."},"deletedAt":{"type":"string","format":"date-time","description":"When it was deleted. ISO 8601 timestamp in UTC."},"deletedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when the account no longer exists.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who deleted it."},"stageTwoAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the entry reached stage 2, or null. ISO 8601 timestamp in UTC."},"removedAt":{"type":"string","format":"date-time","description":"When the entry will be deleted permanently, by the current retention settings. ISO 8601 timestamp in UTC."},"formerParentEntryId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The trash entry of the page or folder this item was below, when that one is in the same trash list; restoring with `withParents=true` restores both. Null otherwise."}},"required":["id","spaceId","spaceKey","spaceName","kind","itemId","number","itemKind","title","descendants","stage","deletedAt","deletedBy","stageTwoAt","removedAt","formerParentEntryId"],"additionalProperties":false,"description":"An entry of the trash."},"description":"Trash entries."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","kind":"items","itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a41","number":1041,"itemKind":"page","title":"Old VPN (OpenVPN) setup","descendants":2,"stage":2,"deletedAt":"2026-10-02T10:00:00.000Z","deletedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Lukas Hofer"},"stageTwoAt":null,"removedAt":"2027-02-14T10:00:00.000Z","formerParentEntryId":null}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/trash/{entryId}/delete":{"post":{"operationId":"trash.deleteInOrganization","summary":"Delete content permanently at once","description":"Deletes a trash entry or a deleted space permanently without waiting for the retention periods, for example for a legal erasure request. Requires a reason, which goes into the audit log. This cannot be undone.\n\nRequires the permission `organization.trash.manage` on the organization in `organizationId`. Needs a signed-in session; API tokens are refused.","tags":["Trash"],"x-lunedo-permission":{"action":"organization.trash.manage","resource":"organization","parameter":"organizationId"},"security":[{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"entryId","in":"path","required":true,"description":"ID of the trash entry.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":1000,"description":"Why the content must be deleted at once, for example a legal erasure request. 1 to 500 characters; it goes into the audit log."}},"required":["reason"],"additionalProperties":false,"description":"The reason for deleting permanently at once."},"example":{"reason":"Erasure request of 6 Oct 2026, ticket 4711"}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`invalidInput`: The request is not valid. `reasonRequired`: A reason is required.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"reasonRequired":{"value":{"type":"urn:lunedo:problem:reasonRequired","title":"A reason is required","status":400,"code":"reasonRequired"}}}}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `reauthenticationRequired`: Confirm your identity first. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"reauthenticationRequired":{"value":{"type":"urn:lunedo:problem:reauthenticationRequired","title":"Confirm your identity first","status":403,"code":"reauthenticationRequired"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/trash/{entryId}/restore":{"post":{"operationId":"trash.restoreInOrganization","summary":"Restore deleted content of an organization","description":"Restores a trash entry of either stage or a deleted space. Items return to their old place or the top level of their space. Confidential spaces are not reachable here; only their own space admins restore their content. When the former parent page is in the trash and the content would lose a view restriction it inherited, the restore is refused with `restrictedParentInTrash`; repeat it with `withParents=true` to restore the parent pages with it. `withParents=true` also restores a former parent page that is in the trash without a restriction, so the content returns below it.\n\nRequires the permission `organization.trash.manage` on the organization in `organizationId`.","tags":["Trash"],"x-lunedo-permission":{"action":"organization.trash.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"entryId","in":"path","required":true,"description":"ID of the trash entry.","schema":{"type":"string","format":"uuid"}},{"name":"withParents","in":"query","required":false,"description":"`true` also restores the former parent pages from the trash when the content would otherwise lose a view restriction it inherited. It needs the right to restore each of them.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"Where it went.","content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The restored item, or null for a space."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the restored item in the addresses of the app, or null for a space."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Where the item went: its parent, or null for the top level."},"parentEntries":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of trash entries of former parent pages restored with it, so it keeps the view restrictions it inherited."}},"required":["itemId","number","parentId","parentEntries"],"additionalProperties":false,"description":"Where the restored content went."},"example":{"itemId":null,"number":null,"parentId":null,"parentEntries":0}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`restrictedParentInTrash`: The content was below a restricted page that is in the trash.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"restrictedParentInTrash":{"value":{"type":"urn:lunedo:problem:restrictedParentInTrash","title":"The content was below a restricted page that is in the trash","status":409,"code":"restrictedParentInTrash"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/organizations/{organizationId}/trash/confidential-spaces":{"get":{"operationId":"trash.deletedConfidentialSpaces","summary":"Count deleted confidential spaces","description":"Counts the deleted confidential spaces of the organization. Organization administrators cannot see or restore them; only the people who were their space admins at deletion can.\n\nRequires the permission `organization.trash.manage` on the organization in `organizationId`.","tags":["Trash"],"x-lunedo-permission":{"action":"organization.trash.manage","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The number.","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of deleted confidential spaces that their former space admins can still restore."}},"required":["deleted"],"additionalProperties":false,"description":"Deleted confidential spaces, counted without names or keys."},"example":{"deleted":1}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/organizations/{organizationId}/unowned-items":{"get":{"operationId":"ownership.organizationUnowned","summary":"List items without an owner in an organization","description":"Lists items without an active owner in the spaces of the organization that the caller can read, without confidential spaces. `hidden` counts items the caller cannot open.\n\nRequires the permission `organization.spaces.view` on the organization in `organizationId`.","tags":["Ownership and status"],"x-lunedo-permission":{"action":"organization.spaces.view","resource":"organization","parameter":"organizationId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"organizationId","in":"path","required":true,"description":"ID of the organization.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Cursor from `nextCursor` of the previous page.","schema":{"type":"string","maxLength":2000}}],"responses":{"200":{"description":"The items.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the item."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app."},"spaceId":{"type":"string","format":"uuid","description":"Space of the item."},"spaceKey":{"type":"string","description":"Key of the space."},"spaceName":{"type":"string","description":"Name of the space."},"kind":{"type":"string","description":"Kind of the item. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title of the item."},"formerOwner":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the person."},"name":{"description":"Name of the person, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"The owner who left, or null when the item never had one."},"reason":{"type":"string","enum":["none","deactivated","membershipEnded"],"description":"Why the item has no owner: `none` (never had one), `deactivated` (the account was deactivated) or `membershipEnded` (the person is no longer a member of the organization)."}},"required":["id","number","spaceId","spaceKey","spaceName","kind","title","formerOwner","reason"],"additionalProperties":false,"description":"An item without an active owner."},"description":"Items, by title, up to 100 per page."},"hidden":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of further items without an owner that the caller cannot open, for example restricted pages. Remove their restriction or ask someone who can open them."},"nextCursor":{"description":"Cursor for the next page, or null on the last page.","type":["string","null"]}},"required":["items","hidden","nextCursor"],"additionalProperties":false,"description":"Items without an active owner."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":1042,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a30","spaceKey":"ITOPS","spaceName":"IT Operations","kind":"page","title":"Restart the VPN gateway","formerOwner":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Weber"},"reason":"deactivated"}],"hidden":0,"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/pages/{pageId}/access":{"get":{"operationId":"pageAccess.get","summary":"Get the access of a page","description":"Lists the people and groups the page is shared with, its restrictions and the people who opened it through a share link.\n\nRequires the permission `item.share` on the item in `pageId`.","tags":["Page access"],"x-lunedo-permission":{"action":"item.share","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The access of the page.","content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"ID of the page."},"title":{"type":"string","description":"Title of the page."},"shares":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the access entry."},"holder":{"type":"object","properties":{"kind":{"type":"string","enum":["account","group"],"description":"`account` for a person, `group` for a group."},"id":{"type":"string","format":"uuid","description":"ID of the account or group."},"name":{"description":"Name of the person or group, or null when hidden.","type":["string","null"]},"email":{"description":"E-mail address, when the caller may see it.","type":["string","null"]},"members":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Active members of a group; null for people."},"active":{"type":"boolean","description":"Whether the account is active or the group still exists."}},"required":["kind","id","name","email","members","active"],"additionalProperties":false,"description":"A person or group with access to a page."},"role":{"type":"string","enum":["reader","commenter","editor"],"description":"`reader` reads, `commenter` also comments, `editor` also edits, moves and deletes."},"includeDescendants":{"type":"boolean","description":"Whether the entry also covers the pages below."},"spaceRole":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"]},{"type":"null"}],"description":"Role of the person in the space, or null when the entry is their only access."},"sharedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who added the entry."},"createdAt":{"type":"string","format":"date-time","description":"When it was added. ISO 8601 timestamp in UTC."}},"required":["id","holder","role","includeDescendants","spaceRole","sharedBy","createdAt"],"additionalProperties":false,"description":"An entry of the access list."},"description":"The access list: people and groups the page is shared with. Restrictions limit access to it."},"restrictions":{"type":"object","properties":{"view":{"anyOf":[{"type":"object","properties":{"setBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who set it."},"setAt":{"type":"string","format":"date-time","description":"When it was set. ISO 8601 timestamp in UTC."}},"required":["setBy","setAt"],"additionalProperties":false,"description":"A restriction of the page itself."},{"type":"null"}],"description":"Set when only the access list may view the page and the pages below."},"edit":{"anyOf":[{"type":"object","properties":{"setBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who set it."},"setAt":{"type":"string","format":"date-time","description":"When it was set. ISO 8601 timestamp in UTC."}},"required":["setBy","setAt"],"additionalProperties":false,"description":"A restriction of the page itself."},{"type":"null"}],"description":"Set when only entries with `editor` may edit the page."},"inherited":{"type":"array","items":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"Restricted page above."},"title":{"description":"Its title, or null when the caller cannot see it.","type":["string","null"]}},"required":["itemId","title"],"additionalProperties":false,"description":"A restricted page above this one."},"description":"View restrictions of pages above, which apply to this page as well."},"holders":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["view","edit"],"description":"The restriction the entry is named in."},"holder":{"type":"object","properties":{"kind":{"type":"string","enum":["account","group"],"description":"`account` for a person, `group` for a group."},"id":{"type":"string","format":"uuid","description":"ID of the account or group."},"name":{"description":"Name of the person or group, or null when hidden.","type":["string","null"]},"email":{"description":"E-mail address, when the caller may see it.","type":["string","null"]},"members":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Active members of a group; null for people."},"active":{"type":"boolean","description":"Whether the account is active or the group still exists."}},"required":["kind","id","name","email","members","active"],"additionalProperties":false,"description":"A person or group with access to a page."}},"required":["kind","holder"],"additionalProperties":false,"description":"A person or group named in a restriction."},"description":"People and groups named in a restriction without an entry in the access list, such as from an import. They pass the restriction but get no access from it: they still need a role in the space."}},"required":["view","edit","inherited","holders"],"additionalProperties":false,"description":"Restrictions of the page."},"linkVisitors":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]},"linkId":{"type":"string","format":"uuid","description":"The share link they opened."},"lastOpenedAt":{"type":"string","format":"date-time","description":"When they last opened it. ISO 8601 timestamp in UTC."}},"required":["accountId","name","linkId","lastOpenedAt"],"additionalProperties":false,"description":"A signed-in person with access through a share link."},"description":"People with access only through share links, marked as via link in the interface."},"canInviteGuests":{"type":"boolean","description":"Whether the caller may invite a guest by e-mail to this page."}},"required":["itemId","title","shares","restrictions","linkVisitors","canInviteGuests"],"additionalProperties":false,"description":"Who has access to a page beyond the roles of its space."},"example":{"itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","title":"VPN access for remote staff","shares":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a50","holder":{"kind":"account","id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger","email":"anna.berger@example.org","members":null,"active":true},"role":"editor","includeDescendants":false,"spaceRole":null,"sharedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a21","name":"Lukas Hofer"},"createdAt":"2026-10-01T09:30:00.000Z"}],"restrictions":{"view":null,"edit":null,"inherited":[],"holders":[]},"linkVisitors":[],"canInviteGuests":false}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"pageAccess.change","summary":"Change the access of a page","description":"Shares the page, changes or removes access entries and sets or removes restrictions, all at once. Restrictions only narrow access: a view restriction lets only the access list see the page and the pages below, an edit restriction lets only entries with `editor` edit the page. People the page is shared with get a notification.\n\nRequires the permission `item.share` on the item in `pageId`.","tags":["Page access"],"x-lunedo-permission":{"action":"item.share","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"changes":{"minItems":1,"maxItems":50,"type":"array","items":{"oneOf":[{"type":"object","properties":{"action":{"type":"string","const":"share","description":"Add a person or group to the access list."},"holderKind":{"type":"string","enum":["account","group"],"description":"`account` for a person, `group` for a group."},"holderId":{"type":"string","format":"uuid","description":"ID of the account or group."},"role":{"type":"string","enum":["reader","commenter","editor"],"description":"`reader` reads, `commenter` also comments, `editor` also edits, moves and deletes."},"includeDescendants":{"default":false,"description":"Also give access to the pages below. Default false.","type":"boolean"}},"required":["action","holderKind","holderId","role"],"additionalProperties":false,"description":"Shares the page."},{"type":"object","properties":{"action":{"type":"string","const":"changeShare","description":"Change an entry of the access list."},"shareId":{"type":"string","format":"uuid","description":"ID of the access entry."},"role":{"type":"string","enum":["reader","commenter","editor"],"description":"`reader` reads, `commenter` also comments, `editor` also edits, moves and deletes."},"includeDescendants":{"description":"Also give access to the pages below.","type":"boolean"}},"required":["action","shareId"],"additionalProperties":false,"description":"Changes an entry."},{"type":"object","properties":{"action":{"type":"string","const":"removeShare","description":"Remove an entry of the access list."},"shareId":{"type":"string","format":"uuid","description":"ID of the access entry."}},"required":["action","shareId"],"additionalProperties":false,"description":"Removes an entry."},{"type":"object","properties":{"action":{"type":"string","const":"restrict","description":"Restrict the page."},"kind":{"type":"string","enum":["view","edit"],"description":"`view` restricts viewing of the page and the pages below, `edit` editing of the page."}},"required":["action","kind"],"additionalProperties":false,"description":"Restricts the page. The caller is added to the access list with `editor`."},{"type":"object","properties":{"action":{"type":"string","const":"unrestrict","description":"Remove a restriction."},"kind":{"type":"string","enum":["view","edit"],"description":"Which restriction."}},"required":["action","kind"],"additionalProperties":false,"description":"Removes a restriction."}],"description":"A change of the access to a page."},"description":"Changes, applied together and in order."}},"required":["changes"],"additionalProperties":false,"description":"Changes of the access to a page."},"example":{"changes":[{"action":"share","holderKind":"account","holderId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","role":"editor"}]}}}},"responses":{"200":{"description":"The access after the change.","content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"ID of the page."},"title":{"type":"string","description":"Title of the page."},"shares":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the access entry."},"holder":{"type":"object","properties":{"kind":{"type":"string","enum":["account","group"],"description":"`account` for a person, `group` for a group."},"id":{"type":"string","format":"uuid","description":"ID of the account or group."},"name":{"description":"Name of the person or group, or null when hidden.","type":["string","null"]},"email":{"description":"E-mail address, when the caller may see it.","type":["string","null"]},"members":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Active members of a group; null for people."},"active":{"type":"boolean","description":"Whether the account is active or the group still exists."}},"required":["kind","id","name","email","members","active"],"additionalProperties":false,"description":"A person or group with access to a page."},"role":{"type":"string","enum":["reader","commenter","editor"],"description":"`reader` reads, `commenter` also comments, `editor` also edits, moves and deletes."},"includeDescendants":{"type":"boolean","description":"Whether the entry also covers the pages below."},"spaceRole":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"]},{"type":"null"}],"description":"Role of the person in the space, or null when the entry is their only access."},"sharedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who added the entry."},"createdAt":{"type":"string","format":"date-time","description":"When it was added. ISO 8601 timestamp in UTC."}},"required":["id","holder","role","includeDescendants","spaceRole","sharedBy","createdAt"],"additionalProperties":false,"description":"An entry of the access list."},"description":"The access list: people and groups the page is shared with. Restrictions limit access to it."},"restrictions":{"type":"object","properties":{"view":{"anyOf":[{"type":"object","properties":{"setBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who set it."},"setAt":{"type":"string","format":"date-time","description":"When it was set. ISO 8601 timestamp in UTC."}},"required":["setBy","setAt"],"additionalProperties":false,"description":"A restriction of the page itself."},{"type":"null"}],"description":"Set when only the access list may view the page and the pages below."},"edit":{"anyOf":[{"type":"object","properties":{"setBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who set it."},"setAt":{"type":"string","format":"date-time","description":"When it was set. ISO 8601 timestamp in UTC."}},"required":["setBy","setAt"],"additionalProperties":false,"description":"A restriction of the page itself."},{"type":"null"}],"description":"Set when only entries with `editor` may edit the page."},"inherited":{"type":"array","items":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"Restricted page above."},"title":{"description":"Its title, or null when the caller cannot see it.","type":["string","null"]}},"required":["itemId","title"],"additionalProperties":false,"description":"A restricted page above this one."},"description":"View restrictions of pages above, which apply to this page as well."},"holders":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["view","edit"],"description":"The restriction the entry is named in."},"holder":{"type":"object","properties":{"kind":{"type":"string","enum":["account","group"],"description":"`account` for a person, `group` for a group."},"id":{"type":"string","format":"uuid","description":"ID of the account or group."},"name":{"description":"Name of the person or group, or null when hidden.","type":["string","null"]},"email":{"description":"E-mail address, when the caller may see it.","type":["string","null"]},"members":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Active members of a group; null for people."},"active":{"type":"boolean","description":"Whether the account is active or the group still exists."}},"required":["kind","id","name","email","members","active"],"additionalProperties":false,"description":"A person or group with access to a page."}},"required":["kind","holder"],"additionalProperties":false,"description":"A person or group named in a restriction."},"description":"People and groups named in a restriction without an entry in the access list, such as from an import. They pass the restriction but get no access from it: they still need a role in the space."}},"required":["view","edit","inherited","holders"],"additionalProperties":false,"description":"Restrictions of the page."},"linkVisitors":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]},"linkId":{"type":"string","format":"uuid","description":"The share link they opened."},"lastOpenedAt":{"type":"string","format":"date-time","description":"When they last opened it. ISO 8601 timestamp in UTC."}},"required":["accountId","name","linkId","lastOpenedAt"],"additionalProperties":false,"description":"A signed-in person with access through a share link."},"description":"People with access only through share links, marked as via link in the interface."},"canInviteGuests":{"type":"boolean","description":"Whether the caller may invite a guest by e-mail to this page."}},"required":["itemId","title","shares","restrictions","linkVisitors","canInviteGuests"],"additionalProperties":false,"description":"Who has access to a page beyond the roles of its space."},"example":{"itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","title":"VPN access for remote staff","shares":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a50","holder":{"kind":"account","id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger","email":"anna.berger@example.org","members":null,"active":true},"role":"editor","includeDescendants":false,"spaceRole":null,"sharedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a21","name":"Lukas Hofer"},"createdAt":"2026-10-01T09:30:00.000Z"}],"restrictions":{"view":null,"edit":null,"inherited":[],"holders":[]},"linkVisitors":[],"canInviteGuests":false}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `ownShare`: Nobody changes access they hold themselves. `shareBeyondOwnAccess`: A share cannot reach further than your own access.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"ownShare":{"value":{"type":"urn:lunedo:problem:ownShare","title":"Nobody changes access they hold themselves","status":403,"code":"ownShare"}},"shareBeyondOwnAccess":{"value":{"type":"urn:lunedo:problem:shareBeyondOwnAccess","title":"A share cannot reach further than your own access","status":403,"code":"shareBeyondOwnAccess"}}}}}},"404":{"description":"`notFound`: Not found. `shareNotFound`: The access entry does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"shareNotFound":{"value":{"type":"urn:lunedo:problem:shareNotFound","title":"The access entry does not exist","status":404,"code":"shareNotFound"}}}}}},"409":{"description":"`alreadyShared`: The page is already shared with them. `categoryAccessManaged`: The access of a category is set in its own dialog. `restrictionWithoutEditors`: A page restricted for editing needs someone who can edit it. `restrictionWithoutViewers`: A restricted page needs someone who can view it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"alreadyShared":{"value":{"type":"urn:lunedo:problem:alreadyShared","title":"The page is already shared with them","status":409,"code":"alreadyShared"}},"categoryAccessManaged":{"value":{"type":"urn:lunedo:problem:categoryAccessManaged","title":"The access of a category is set in its own dialog","status":409,"code":"categoryAccessManaged"}},"restrictionWithoutEditors":{"value":{"type":"urn:lunedo:problem:restrictionWithoutEditors","title":"A page restricted for editing needs someone who can edit it","status":409,"code":"restrictionWithoutEditors"}},"restrictionWithoutViewers":{"value":{"type":"urn:lunedo:problem:restrictionWithoutViewers","title":"A restricted page needs someone who can view it","status":409,"code":"restrictionWithoutViewers"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/pages/{pageId}/access-requests":{"post":{"operationId":"accessRequests.requestPage","summary":"Ask for access to a page","description":"Asks for access to a page the caller reached but cannot read. The request goes to the space admins and to the people who restricted the page. The answer is the same whether or not the page exists.\n\nRequires the permission `instance.content.view` on the instance. Needs a signed-in session; API tokens are refused.","tags":["Access requests"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"default":"","description":"Why the access is needed, up to 1000 characters.","type":"string","maxLength":1000}},"additionalProperties":false,"description":"A request for access."},"example":{"message":"I need the runbook for the migration."}}}},"responses":{"202":{"description":"Accepted."},"400":{"description":"`invalidInput`: The request is not valid. `messageTooLong`: The message is too long.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"messageTooLong":{"value":{"type":"urn:lunedo:problem:messageTooLong","title":"The message is too long","status":400,"code":"messageTooLong"}}}}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`tooManyRequests`: Too many access requests today.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"tooManyRequests":{"value":{"type":"urn:lunedo:problem:tooManyRequests","title":"Too many access requests today","status":429,"code":"tooManyRequests"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/pages/{pageId}/access/explain":{"get":{"operationId":"pageAccess.explain","summary":"Explain why someone has access to a page","description":"Lists the roles, shares and links that give the person access, and the restrictions that narrow it.\n\nRequires the permission `item.share` on the item in `pageId`.","tags":["Page access"],"x-lunedo-permission":{"action":"item.share","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}},{"name":"accountId","in":"query","required":true,"description":"The person.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The explanation.","content":{"application/json":{"schema":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"The person."},"name":{"description":"Name, or null when hidden.","type":["string","null"]},"role":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"]},{"type":"null"}],"description":"What the person may do, or null for no access."},"reasons":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"Kind of reason. New values can be added in later versions; handle unknown values.","x-extensible-enum":["spaceRole","share","link"]},"role":{"description":"Role that the reason grants.","type":"string","enum":["reader","commenter","editor","admin"]},"via":{"type":"object","properties":{"type":{"type":"string","description":"How the role is held. New values can be added in later versions; handle unknown values.","x-extensible-enum":["account","group","organizationMembers","instanceUsers","visibility"]},"groupId":{"type":"string","format":"uuid","description":"The group."},"name":{"description":"Name of the group.","type":"string"},"visibility":{"description":"Visibility of the space that grants the role.","type":"string"}},"required":["type"],"additionalProperties":false,"description":"How a role in the space is held."},"itemId":{"type":"string","format":"uuid","description":"Page that was shared."},"itemTitle":{"description":"Its title, or null when the caller cannot see it.","type":["string","null"]},"inherited":{"description":"Whether the share comes from a page above.","type":"boolean"},"linkId":{"type":"string","format":"uuid","description":"The share link."},"scope":{"description":"Scope of the share link.","type":"string"},"inactive":{"type":"string","description":"Set when the entry is stored but grants nothing: `membershipEnded` means the person is no longer a member of the organization the space belongs to. It applies again if they become a member again. New values can be added in later versions; handle unknown values.","x-extensible-enum":["membershipEnded"]}},"required":["type"],"additionalProperties":false,"description":"Why a person has access, or an entry that has no effect."},"description":"Why: roles, shares and links."},"denial":{"description":"Why access is missing or narrower: `restricted`, `editRestricted`, `unpublished`, `inTrash`, `accountInactive` or `noAccess`.","type":["string","null"]},"restrictions":{"type":"array","items":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"Restricted page."},"title":{"description":"Its title, or null when hidden.","type":["string","null"]},"listed":{"type":"boolean","description":"Whether the person is on its access list."}},"required":["itemId","title","listed"],"additionalProperties":false,"description":"A view restriction that applies."},"description":"View restrictions on the page and above."},"editRestricted":{"anyOf":[{"type":"object","properties":{"listed":{"type":"boolean","description":"Whether the person may edit by the access list."}},"required":["listed"],"additionalProperties":false},{"type":"null"}],"description":"The edit restriction of the page, if any."},"published":{"type":"boolean","description":"Whether readers can see the page yet."}},"required":["accountId","name","role","reasons","denial","restrictions","editRestricted","published"],"additionalProperties":false,"description":"Why a person has or lacks access."},"example":{"accountId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a22","name":"Lukas Hofer","role":"reader","reasons":[{"type":"spaceRole","role":"reader","via":{"type":"group","groupId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a30","name":"IT Operations"}}],"denial":null,"restrictions":[],"editRestricted":null,"published":true}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `personNotFound`: The person does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"personNotFound":{"value":{"type":"urn:lunedo:problem:personNotFound","title":"The person does not exist","status":404,"code":"personNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/pages/{pageId}/access/invitations":{"post":{"operationId":"pageAccess.invite","summary":"Invite a guest to a page","description":"Invites a person without an account as a guest of the organization and shares the page with them when they accept. Organization administrators can always do this; members only when the organization allows it. In a confidential space only its space administrators invite guests.\n\nRequires the permission `item.share` on the item in `pageId`.","tags":["Page access"],"x-lunedo-permission":{"action":"item.share","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","maxLength":320,"description":"E-mail address of the guest."},"role":{"type":"string","enum":["reader","commenter","editor"],"description":"`reader` reads, `commenter` also comments, `editor` also edits, moves and deletes."},"includeDescendants":{"default":false,"description":"Also give access to the pages below. Default false.","type":"boolean"}},"required":["email","role"],"additionalProperties":false,"description":"A guest to invite to the page."},"example":{"email":"contractor@example.net","role":"reader","includeDescendants":false}}}},"responses":{"201":{"description":"The invitation.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the invitation."},"email":{"type":"string","description":"Invited address."},"expiresAt":{"type":"string","format":"date-time","description":"When the invitation expires. ISO 8601 timestamp in UTC."}},"required":["id","email","expiresAt"],"additionalProperties":false,"description":"The invitation that was sent."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a80","email":"contractor@example.net","expiresAt":"2026-10-15T09:30:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidResponsible`: The responsible person is not valid. `invalidScope`: The link scope cannot be used here.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidResponsible":{"value":{"type":"urn:lunedo:problem:invalidResponsible","title":"The responsible person is not valid","status":400,"code":"invalidResponsible"}},"invalidScope":{"value":{"type":"urn:lunedo:problem:invalidScope","title":"The link scope cannot be used here","status":400,"code":"invalidScope"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`confidentialGuestsBySpaceAdmins`: Only space administrators give guests access to a confidential space. `csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `guestInvitesDisabled`: Members cannot invite guests in this organization. `shareBeyondOwnAccess`: A share cannot reach further than your own access.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"confidentialGuestsBySpaceAdmins":{"value":{"type":"urn:lunedo:problem:confidentialGuestsBySpaceAdmins","title":"Only space administrators give guests access to a confidential space","status":403,"code":"confidentialGuestsBySpaceAdmins"}},"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"guestInvitesDisabled":{"value":{"type":"urn:lunedo:problem:guestInvitesDisabled","title":"Members cannot invite guests in this organization","status":403,"code":"guestInvitesDisabled"}},"shareBeyondOwnAccess":{"value":{"type":"urn:lunedo:problem:shareBeyondOwnAccess","title":"A share cannot reach further than your own access","status":403,"code":"shareBeyondOwnAccess"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/pages/{pageId}/access/mine":{"get":{"operationId":"pageAccess.mine","summary":"Get your own access to a page","description":"Explains the caller's own role on the page.\n\nRequires the permission `item.view` on the item in `pageId`.","tags":["Page access"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The explanation.","content":{"application/json":{"schema":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"The person."},"name":{"description":"Name, or null when hidden.","type":["string","null"]},"role":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"]},{"type":"null"}],"description":"What the person may do, or null for no access."},"reasons":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"Kind of reason. New values can be added in later versions; handle unknown values.","x-extensible-enum":["spaceRole","share","link"]},"role":{"description":"Role that the reason grants.","type":"string","enum":["reader","commenter","editor","admin"]},"via":{"type":"object","properties":{"type":{"type":"string","description":"How the role is held. New values can be added in later versions; handle unknown values.","x-extensible-enum":["account","group","organizationMembers","instanceUsers","visibility"]},"groupId":{"type":"string","format":"uuid","description":"The group."},"name":{"description":"Name of the group.","type":"string"},"visibility":{"description":"Visibility of the space that grants the role.","type":"string"}},"required":["type"],"additionalProperties":false,"description":"How a role in the space is held."},"itemId":{"type":"string","format":"uuid","description":"Page that was shared."},"itemTitle":{"description":"Its title, or null when the caller cannot see it.","type":["string","null"]},"inherited":{"description":"Whether the share comes from a page above.","type":"boolean"},"linkId":{"type":"string","format":"uuid","description":"The share link."},"scope":{"description":"Scope of the share link.","type":"string"},"inactive":{"type":"string","description":"Set when the entry is stored but grants nothing: `membershipEnded` means the person is no longer a member of the organization the space belongs to. It applies again if they become a member again. New values can be added in later versions; handle unknown values.","x-extensible-enum":["membershipEnded"]}},"required":["type"],"additionalProperties":false,"description":"Why a person has access, or an entry that has no effect."},"description":"Why: roles, shares and links."},"denial":{"description":"Why access is missing or narrower: `restricted`, `editRestricted`, `unpublished`, `inTrash`, `accountInactive` or `noAccess`.","type":["string","null"]},"restrictions":{"type":"array","items":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"Restricted page."},"title":{"description":"Its title, or null when hidden.","type":["string","null"]},"listed":{"type":"boolean","description":"Whether the person is on its access list."}},"required":["itemId","title","listed"],"additionalProperties":false,"description":"A view restriction that applies."},"description":"View restrictions on the page and above."},"editRestricted":{"anyOf":[{"type":"object","properties":{"listed":{"type":"boolean","description":"Whether the person may edit by the access list."}},"required":["listed"],"additionalProperties":false},{"type":"null"}],"description":"The edit restriction of the page, if any."},"published":{"type":"boolean","description":"Whether readers can see the page yet."}},"required":["accountId","name","role","reasons","denial","restrictions","editRestricted","published"],"additionalProperties":false,"description":"Why a person has or lacks access."},"example":{"accountId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a22","name":"Lukas Hofer","role":"reader","reasons":[{"type":"spaceRole","role":"reader","via":{"type":"group","groupId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a30","name":"IT Operations"}}],"denial":null,"restrictions":[],"editRestricted":null,"published":true}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/pages/{pageId}/access/preview":{"post":{"operationId":"pageAccess.preview","summary":"Preview a change of page access","description":"Shows who would gain or lose the right to read or edit the page. Nothing is changed.\n\nRequires the permission `item.share` on the item in `pageId`.","tags":["Page access"],"x-lunedo-permission":{"action":"item.share","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"changes":{"minItems":1,"maxItems":50,"type":"array","items":{"oneOf":[{"type":"object","properties":{"action":{"type":"string","const":"share","description":"Add a person or group to the access list."},"holderKind":{"type":"string","enum":["account","group"],"description":"`account` for a person, `group` for a group."},"holderId":{"type":"string","format":"uuid","description":"ID of the account or group."},"role":{"type":"string","enum":["reader","commenter","editor"],"description":"`reader` reads, `commenter` also comments, `editor` also edits, moves and deletes."},"includeDescendants":{"default":false,"description":"Also give access to the pages below. Default false.","type":"boolean"}},"required":["action","holderKind","holderId","role"],"additionalProperties":false,"description":"Shares the page."},{"type":"object","properties":{"action":{"type":"string","const":"changeShare","description":"Change an entry of the access list."},"shareId":{"type":"string","format":"uuid","description":"ID of the access entry."},"role":{"type":"string","enum":["reader","commenter","editor"],"description":"`reader` reads, `commenter` also comments, `editor` also edits, moves and deletes."},"includeDescendants":{"description":"Also give access to the pages below.","type":"boolean"}},"required":["action","shareId"],"additionalProperties":false,"description":"Changes an entry."},{"type":"object","properties":{"action":{"type":"string","const":"removeShare","description":"Remove an entry of the access list."},"shareId":{"type":"string","format":"uuid","description":"ID of the access entry."}},"required":["action","shareId"],"additionalProperties":false,"description":"Removes an entry."},{"type":"object","properties":{"action":{"type":"string","const":"restrict","description":"Restrict the page."},"kind":{"type":"string","enum":["view","edit"],"description":"`view` restricts viewing of the page and the pages below, `edit` editing of the page."}},"required":["action","kind"],"additionalProperties":false,"description":"Restricts the page. The caller is added to the access list with `editor`."},{"type":"object","properties":{"action":{"type":"string","const":"unrestrict","description":"Remove a restriction."},"kind":{"type":"string","enum":["view","edit"],"description":"Which restriction."}},"required":["action","kind"],"additionalProperties":false,"description":"Removes a restriction."}],"description":"A change of the access to a page."},"description":"Changes, applied together and in order."}},"required":["changes"],"additionalProperties":false,"description":"Changes of the access to a page."},"example":{"changes":[{"action":"restrict","kind":"view"}]}}}},"responses":{"200":{"description":"The effect.","content":{"application/json":{"schema":{"type":"object","properties":{"read":{"type":"object","properties":{"gaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who get access."},"losing":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who lose access."},"raised":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role rises."},"lowered":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role drops."},"unlisted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of affected people the caller may not see; they are counted but not listed."},"truncated":{"type":"boolean","description":"Whether `changes` lists only the first 100 people."},"changes":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."},"before":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role before the change, or null for no access."},"after":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role after the change, or null for no access."}},"required":["accountId","name","before","after"],"additionalProperties":false,"description":"How the access of one person changes."},"description":"People whose access changes, ordered by name."}},"required":["gaining","losing","raised","lowered","unlisted","truncated","changes"],"additionalProperties":false,"description":"Who gains or loses the right to read."},"edit":{"type":"object","properties":{"gaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who get access."},"losing":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who lose access."},"raised":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role rises."},"lowered":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role drops."},"unlisted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of affected people the caller may not see; they are counted but not listed."},"truncated":{"type":"boolean","description":"Whether `changes` lists only the first 100 people."},"changes":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."},"before":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role before the change, or null for no access."},"after":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role after the change, or null for no access."}},"required":["accountId","name","before","after"],"additionalProperties":false,"description":"How the access of one person changes."},"description":"People whose access changes, ordered by name."}},"required":["gaining","losing","raised","lowered","unlisted","truncated","changes"],"additionalProperties":false,"description":"Who gains or loses the right to edit."}},"required":["read","edit"],"additionalProperties":false,"description":"How access to the page would change."},"example":{"read":{"gaining":1,"losing":0,"raised":0,"lowered":0,"unlisted":0,"truncated":false,"changes":[{"accountId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger","before":null,"after":"reader"}]},"edit":{"gaining":0,"losing":0,"raised":0,"lowered":0,"unlisted":0,"truncated":false,"changes":[]}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`confidentialGuestsBySpaceAdmins`: Only space administrators give guests access to a confidential space. `csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `ownShare`: Nobody changes access they hold themselves. `shareBeyondOwnAccess`: A share cannot reach further than your own access.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"confidentialGuestsBySpaceAdmins":{"value":{"type":"urn:lunedo:problem:confidentialGuestsBySpaceAdmins","title":"Only space administrators give guests access to a confidential space","status":403,"code":"confidentialGuestsBySpaceAdmins"}},"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"ownShare":{"value":{"type":"urn:lunedo:problem:ownShare","title":"Nobody changes access they hold themselves","status":403,"code":"ownShare"}},"shareBeyondOwnAccess":{"value":{"type":"urn:lunedo:problem:shareBeyondOwnAccess","title":"A share cannot reach further than your own access","status":403,"code":"shareBeyondOwnAccess"}}}}}},"404":{"description":"`notFound`: Not found. `shareNotFound`: The access entry does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"shareNotFound":{"value":{"type":"urn:lunedo:problem:shareNotFound","title":"The access entry does not exist","status":404,"code":"shareNotFound"}}}}}},"409":{"description":"`alreadyShared`: The page is already shared with them. `restrictionWithoutEditors`: A page restricted for editing needs someone who can edit it. `restrictionWithoutViewers`: A restricted page needs someone who can view it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"alreadyShared":{"value":{"type":"urn:lunedo:problem:alreadyShared","title":"The page is already shared with them","status":409,"code":"alreadyShared"}},"restrictionWithoutEditors":{"value":{"type":"urn:lunedo:problem:restrictionWithoutEditors","title":"A page restricted for editing needs someone who can edit it","status":409,"code":"restrictionWithoutEditors"}},"restrictionWithoutViewers":{"value":{"type":"urn:lunedo:problem:restrictionWithoutViewers","title":"A restricted page needs someone who can view it","status":409,"code":"restrictionWithoutViewers"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/pages/{pageId}/attachments":{"get":{"operationId":"attachments.list","summary":"List the attachments of a page","description":"Lists the files attached to a page or blog post with their current version, ordered by name. People who can edit the page get the draft state, with attachments that readers do not see yet marked in `draft`; everyone else gets the attachments of the published version.\n\nRequires the permission `item.view` on the item in `pageId`.","tags":["Attachments"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page or blog post.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The attachments.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the attachment."},"itemId":{"type":"string","format":"uuid","description":"Page or blog post the file is attached to."},"name":{"type":"string","description":"File name of the current version."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the current version in bytes."},"contentType":{"type":"string","description":"Media type, decided from the content of the file."},"preview":{"type":"string","description":"How the file can be previewed; `none` offers only the download. New values can be added in later versions; handle unknown values.","x-extensible-enum":["image","pdf","video","audio","text","code","markdown","csv","svg","word","excel","none"]},"inline":{"type":"boolean","description":"Whether browsers may show the file directly: images, video and audio."},"tooLargeForPreview":{"type":"boolean","description":"Whether the image has more than 100 megapixels. Such images get no smaller version; pages and previews show them as a file that opens in full size."},"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the current version."},"versions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of stored versions."},"draft":{"anyOf":[{"type":"string","x-extensible-enum":["added","changed","deleted"]},{"type":"null"}],"description":"Only for people who can edit the page: `added` when readers do not see the file until the next publication, `changed` when readers still see an earlier version, `deleted` when the file was deleted in the draft and readers still see it until the next publication; restore it to keep it. Null when readers see this version. New values can be added in later versions; handle unknown values."},"uploadedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who uploaded the current version."},"uploadedAt":{"type":"string","format":"date-time","description":"When the current version was uploaded. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the file was first attached. ISO 8601 timestamp in UTC."}},"required":["id","itemId","name","size","contentType","preview","inline","tooLargeForPreview","version","versions","draft","uploadedBy","uploadedAt","createdAt"],"additionalProperties":false,"description":"A file attached to a page or blog post."},"description":"Attachments, ordered by name."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","name":"network-diagram.png","size":48213,"contentType":"image/png","preview":"image","inline":true,"tooLargeForPreview":false,"version":2,"versions":2,"draft":null,"uploadedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"uploadedAt":"2026-10-01T09:30:00.000Z","createdAt":"2026-09-28T14:02:00.000Z"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"attachments.upload","summary":"Upload a file","description":"Attaches a file to a page or blog post. Send the bytes as the request body with `Content-Type: application/octet-stream` and the name in `name`. Files above the size limit of the organization are refused before anything is stored. A file with the same name becomes a new version of that attachment.\n\nRequires the permission `item.edit` on the item in `pageId`.","tags":["Attachments"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page or blog post.","schema":{"type":"string","format":"uuid"}},{"name":"name","in":"query","required":true,"description":"File name. Paths and control characters are removed. A file with the same name, compared without case, becomes a new version.","schema":{"type":"string","minLength":1,"maxLength":1020}}],"requestBody":{"required":true,"description":"The bytes of the file.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"201":{"description":"The attachment with the new version.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the attachment."},"itemId":{"type":"string","format":"uuid","description":"Page or blog post the file is attached to."},"name":{"type":"string","description":"File name of the current version."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the current version in bytes."},"contentType":{"type":"string","description":"Media type, decided from the content of the file."},"preview":{"type":"string","description":"How the file can be previewed; `none` offers only the download. New values can be added in later versions; handle unknown values.","x-extensible-enum":["image","pdf","video","audio","text","code","markdown","csv","svg","word","excel","none"]},"inline":{"type":"boolean","description":"Whether browsers may show the file directly: images, video and audio."},"tooLargeForPreview":{"type":"boolean","description":"Whether the image has more than 100 megapixels. Such images get no smaller version; pages and previews show them as a file that opens in full size."},"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the current version."},"versions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of stored versions."},"draft":{"anyOf":[{"type":"string","x-extensible-enum":["added","changed","deleted"]},{"type":"null"}],"description":"Only for people who can edit the page: `added` when readers do not see the file until the next publication, `changed` when readers still see an earlier version, `deleted` when the file was deleted in the draft and readers still see it until the next publication; restore it to keep it. Null when readers see this version. New values can be added in later versions; handle unknown values."},"uploadedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who uploaded the current version."},"uploadedAt":{"type":"string","format":"date-time","description":"When the current version was uploaded. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the file was first attached. ISO 8601 timestamp in UTC."}},"required":["id","itemId","name","size","contentType","preview","inline","tooLargeForPreview","version","versions","draft","uploadedBy","uploadedAt","createdAt"],"additionalProperties":false,"description":"A file attached to a page or blog post."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","name":"network-diagram.png","size":48213,"contentType":"image/png","preview":"image","inline":true,"tooLargeForPreview":false,"version":2,"versions":2,"draft":null,"uploadedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"uploadedAt":"2026-10-01T09:30:00.000Z","createdAt":"2026-09-28T14:02:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidFileName`: The file name is not valid. `invalidInput`: The request is not valid. `invalidItem`: Files can only be attached to pages, blog posts and whiteboards.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidFileName":{"value":{"type":"urn:lunedo:problem:invalidFileName","title":"The file name is not valid","status":400,"code":"invalidFileName"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidItem":{"value":{"type":"urn:lunedo:problem:invalidItem","title":"Files can only be attached to pages, blog posts and whiteboards","status":400,"code":"invalidItem"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"413":{"description":"`fileTooLarge`: The file is larger than allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"fileTooLarge":{"value":{"type":"urn:lunedo:problem:fileTooLarge","title":"The file is larger than allowed","status":413,"code":"fileTooLarge"}}}}}},"415":{"description":"`unsupportedMediaType`: The request body has an unsupported type.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unsupportedMediaType":{"value":{"type":"urn:lunedo:problem:unsupportedMediaType","title":"The request body has an unsupported type","status":415,"code":"unsupportedMediaType"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}},"507":{"description":"`storageFull`: Storage is almost full.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"storageFull":{"value":{"type":"urn:lunedo:problem:storageFull","title":"Storage is almost full","status":507,"code":"storageFull"}}}}}}}}},"/api/v1/pages/{pageId}/attachments/{attachmentId}/restore":{"post":{"operationId":"attachments.undelete","summary":"Bring back a deleted attachment","description":"Undoes the deletion of an attachment of this page, also of one deleted in the draft that readers still see until the next publication.\n\nRequires the permission `item.edit` on the item in `pageId`.","tags":["Attachments"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page or blog post.","schema":{"type":"string","format":"uuid"}},{"name":"attachmentId","in":"path","required":true,"description":"ID of the deleted attachment.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The attachment.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the attachment."},"itemId":{"type":"string","format":"uuid","description":"Page or blog post the file is attached to."},"name":{"type":"string","description":"File name of the current version."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the current version in bytes."},"contentType":{"type":"string","description":"Media type, decided from the content of the file."},"preview":{"type":"string","description":"How the file can be previewed; `none` offers only the download. New values can be added in later versions; handle unknown values.","x-extensible-enum":["image","pdf","video","audio","text","code","markdown","csv","svg","word","excel","none"]},"inline":{"type":"boolean","description":"Whether browsers may show the file directly: images, video and audio."},"tooLargeForPreview":{"type":"boolean","description":"Whether the image has more than 100 megapixels. Such images get no smaller version; pages and previews show them as a file that opens in full size."},"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the current version."},"versions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of stored versions."},"draft":{"anyOf":[{"type":"string","x-extensible-enum":["added","changed","deleted"]},{"type":"null"}],"description":"Only for people who can edit the page: `added` when readers do not see the file until the next publication, `changed` when readers still see an earlier version, `deleted` when the file was deleted in the draft and readers still see it until the next publication; restore it to keep it. Null when readers see this version. New values can be added in later versions; handle unknown values."},"uploadedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who uploaded the current version."},"uploadedAt":{"type":"string","format":"date-time","description":"When the current version was uploaded. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the file was first attached. ISO 8601 timestamp in UTC."}},"required":["id","itemId","name","size","contentType","preview","inline","tooLargeForPreview","version","versions","draft","uploadedBy","uploadedAt","createdAt"],"additionalProperties":false,"description":"A file attached to a page or blog post."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","name":"network-diagram.png","size":48213,"contentType":"image/png","preview":"image","inline":true,"tooLargeForPreview":false,"version":2,"versions":2,"draft":null,"uploadedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"uploadedAt":"2026-10-01T09:30:00.000Z","createdAt":"2026-09-28T14:02:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`attachmentNotFound`: The file does not exist. `notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"attachmentNotFound":{"value":{"type":"urn:lunedo:problem:attachmentNotFound","title":"The file does not exist","status":404,"code":"attachmentNotFound"}},"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`nameTaken`: A file with this name exists.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"nameTaken":{"value":{"type":"urn:lunedo:problem:nameTaken","title":"A file with this name exists","status":409,"code":"nameTaken"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/pages/{pageId}/backlinks":{"get":{"operationId":"items.backlinks","summary":"List the pages that link to a page","description":"Lists the pages with a link to this page, as far as the caller can read them.\n\nRequires the permission `item.view` on the item in `pageId`.","tags":["Pages"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Pages that link here.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"Page that links here."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of that page in the addresses of the app."},"title":{"type":"string","description":"Title of that page."},"spaceId":{"type":"string","format":"uuid","description":"Space of that page."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."}},"required":["itemId","number","title","spaceId","spaceKey","spaceName"],"additionalProperties":false,"description":"A page that links to this page."},"description":"Pages, ordered by title."},"example":[{"itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"title":"Onboarding new staff","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/pages/{pageId}/comments":{"get":{"operationId":"comments.list","summary":"List the comments of a page","description":"Lists page comments and inline comments with their replies, oldest first, up to 2000. Inline comments on text that exists only in the draft are visible to editors only, until the text is published.\n\nRequires the permission `item.view` on the item in `pageId`.","tags":["Comments"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page or blog post.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The comments.","content":{"application/json":{"schema":{"type":"object","properties":{"threads":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the comment."},"itemId":{"type":"string","format":"uuid","description":"Page or blog post the comment belongs to."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The comment this replies to, or null for a new thread."},"author":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null without one. Changes whenever the picture changes; load the picture from `GET /api/v1/accounts/{accountId}/picture`.","type":["string","null"]}},"required":["id","name","pictureRef"],"additionalProperties":false},{"type":"null"}],"description":"Author, or null for a deleted comment."},"body":{"anyOf":[{"description":"Comment content as ProseMirror JSON with the reduced comment schema: paragraphs with bold, italic, underline, strike, subscript, superscript, inline code and links, mentions, bullet and numbered lists and code blocks. No tables, images or headings.","$ref":"#/components/schemas/Schema113ae44d8375"},{"type":"null"}],"description":"Content, or null for a deleted comment."},"deleted":{"type":"boolean","description":"Whether the comment was deleted. A deleted comment with replies stays as a placeholder."},"createdAt":{"type":"string","format":"date-time","description":"When the comment was written. ISO 8601 timestamp in UTC."},"editedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the author last changed it, or null. ISO 8601 timestamp in UTC."},"reactions":{"type":"array","items":{"type":"object","properties":{"emoji":{"type":"string","description":"The emoji."},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many people reacted with it."},"reacted":{"type":"boolean","description":"Whether the caller reacted with it."},"people":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"The first 20 people who reacted, in order."}},"required":["emoji","count","reacted","people"],"additionalProperties":false,"description":"One emoji with the people who reacted with it."},"description":"Reactions, empty when reactions are turned off."},"quote":{"description":"For inline comments, the text the comment refers to; for comments on a whiteboard element, the text of the element (possibly empty). Readers see inline comments only once their text is published.","type":["string","null"]},"anchor":{"type":"string","description":"`page` for a comment on the whole page or whiteboard, `inline` for a comment on text in it, `element` for a comment on an element of a whiteboard, `detached` for a comment whose text or element no longer exists. Detached comments are listed with the page comments. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","inline","element","detached"]},"elementId":{"description":"The whiteboard element the comment refers to, also after it was removed, or null.","type":["string","null"]},"resolvedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the inline comment was resolved, or null while it is open. ISO 8601 timestamp in UTC."},"resolvedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null without one. Changes whenever the picture changes; load the picture from `GET /api/v1/accounts/{accountId}/picture`.","type":["string","null"]}},"required":["id","name","pictureRef"],"additionalProperties":false},{"type":"null"}],"description":"Who resolved it, or null."},"replies":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the comment."},"itemId":{"type":"string","format":"uuid","description":"Page or blog post the comment belongs to."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The comment this replies to, or null for a new thread."},"author":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null without one. Changes whenever the picture changes; load the picture from `GET /api/v1/accounts/{accountId}/picture`.","type":["string","null"]}},"required":["id","name","pictureRef"],"additionalProperties":false},{"type":"null"}],"description":"Author, or null for a deleted comment."},"body":{"anyOf":[{"description":"Comment content as ProseMirror JSON with the reduced comment schema: paragraphs with bold, italic, underline, strike, subscript, superscript, inline code and links, mentions, bullet and numbered lists and code blocks. No tables, images or headings.","$ref":"#/components/schemas/Schema113ae44d8375"},{"type":"null"}],"description":"Content, or null for a deleted comment."},"deleted":{"type":"boolean","description":"Whether the comment was deleted. A deleted comment with replies stays as a placeholder."},"createdAt":{"type":"string","format":"date-time","description":"When the comment was written. ISO 8601 timestamp in UTC."},"editedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the author last changed it, or null. ISO 8601 timestamp in UTC."},"reactions":{"type":"array","items":{"type":"object","properties":{"emoji":{"type":"string","description":"The emoji."},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many people reacted with it."},"reacted":{"type":"boolean","description":"Whether the caller reacted with it."},"people":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"The first 20 people who reacted, in order."}},"required":["emoji","count","reacted","people"],"additionalProperties":false,"description":"One emoji with the people who reacted with it."},"description":"Reactions, empty when reactions are turned off."}},"required":["id","itemId","parentId","author","body","deleted","createdAt","editedAt","reactions"],"additionalProperties":false,"description":"A reply."},"description":"Replies, oldest first. Replies are one level deep."}},"required":["id","itemId","parentId","author","body","deleted","createdAt","editedAt","reactions","quote","anchor","elementId","resolvedAt","resolvedBy","replies"],"additionalProperties":false,"description":"A comment with its replies."},"description":"Threads, oldest first."},"people":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","description":"Name of the person."},"description":"Names of people mentioned in the comments that the caller may see, by account ID."}},"required":["threads","people"],"additionalProperties":false,"description":"Comments of a page."},"example":{"threads":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5b01","itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","parentId":null,"author":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Lukas Hofer","pictureRef":null},"body":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Happened twice this week."}]}]},"deleted":false,"createdAt":"2026-10-06T08:00:00.000Z","editedAt":null,"reactions":[],"quote":"Hotel Wi-Fi blocks UDP 51820","anchor":"inline","elementId":null,"resolvedAt":null,"resolvedBy":null,"replies":[]}],"people":{}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"comments.create","summary":"Comment on a page","description":"Adds a comment on the whole page or whiteboard, with an anchor on text in a page, or with an element ID on an element of a whiteboard. An inline comment marks the text in the draft, or in the current content in live mode; readers see the mark with the next publication. Mentioned people who can read the page are notified at once.\n\nRequires the permission `item.comment` on the item in `pageId`.","tags":["Comments"],"x-lunedo-permission":{"action":"item.comment","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page or blog post.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"description":"Comment content as ProseMirror JSON with the reduced comment schema: paragraphs with bold, italic, underline, strike, subscript, superscript, inline code and links, mentions, bullet and numbered lists and code blocks. No tables, images or headings.","$ref":"#/components/schemas/Schema113ae44d8375"},"anchor":{"description":"Text the comment refers to. Leave it out for a page comment.","type":"object","properties":{"exact":{"type":"string","minLength":1,"maxLength":1000,"description":"The selected text, up to 1000 characters within one paragraph."},"prefix":{"default":"","description":"Up to 64 characters directly before the selection in the same paragraph.","type":"string","maxLength":64},"suffix":{"default":"","description":"Up to 64 characters directly after the selection in the same paragraph.","type":"string","maxLength":64}},"required":["exact"],"additionalProperties":false},"elementId":{"description":"ID of the whiteboard element the comment refers to. Only for whiteboards.","type":"string","pattern":"^[A-Za-z0-9_-]{1,128}$"}},"required":["body"],"additionalProperties":false,"description":"A new comment."},"example":{"body":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Happened twice this week."}]}]},"anchor":{"exact":"Hotel Wi-Fi blocks UDP 51820","prefix":"","suffix":""}}}}},"responses":{"201":{"description":"The new comment.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the new comment."}},"required":["id"],"additionalProperties":false,"description":"The new comment."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5b01"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidAnchor`: The selected text cannot carry a comment. `invalidComment`: The comment does not match the comment schema. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidAnchor":{"value":{"type":"urn:lunedo:problem:invalidAnchor","title":"The selected text cannot carry a comment","status":400,"code":"invalidAnchor"}},"invalidComment":{"value":{"type":"urn:lunedo:problem:invalidComment","title":"The comment does not match the comment schema","status":400,"code":"invalidComment"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`anchorNotFound`: The selected text or element no longer exists. `tooManyComments`: The page has too many comments.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"anchorNotFound":{"value":{"type":"urn:lunedo:problem:anchorNotFound","title":"The selected text or element no longer exists","status":409,"code":"anchorNotFound"}},"tooManyComments":{"value":{"type":"urn:lunedo:problem:tooManyComments","title":"The page has too many comments","status":409,"code":"tooManyComments"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/pages/{pageId}/compare":{"get":{"operationId":"versions.compare","summary":"Compare two versions","description":"Compares two versions, or a version with the draft: text, formatting, tables, callouts, code, formulas, tasks, title and moved blocks.\n\nRequires the permission `item.view` on the item in `pageId`.","tags":["Versions"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}},{"name":"from","in":"query","required":true,"description":"Older side: a version number or `draft`. The draft needs edit permission.","schema":{"anyOf":[{"type":"string","const":"draft"},{"type":"integer","minimum":1,"maximum":9007199254740991}]}},{"name":"to","in":"query","required":true,"description":"Newer side: a version number or `draft`. The draft needs edit permission.","schema":{"anyOf":[{"type":"string","const":"draft"},{"type":"integer","minimum":1,"maximum":9007199254740991}]}}],"responses":{"200":{"description":"The comparison.","content":{"application/json":{"schema":{"type":"object","properties":{"diff":{"description":"The comparison: `title` (before and after, or null), `blocks` (each with `change` of `unchanged`, `added`, `removed`, `changed` or `moved`, the `before` and `after` nodes, changed `attributes`, and for changed blocks `inline` segments, code `lines` or `children`) and the number of `changes`.","$ref":"#/components/schemas/Schema113ae44d8375"},"before":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schemafbc378f59d82"},"after":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schemafbc378f59d82"},"references":{"type":"object","properties":{"people":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","description":"Name of the person."},"description":"Names of mentioned people the caller may see, by account ID."},"pictures":{"description":"Profile pictures of the people in `people` that have one, by account ID. The picture is at `/api/v1/accounts/{accountId}/picture`.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","description":"Version of the profile picture."}},"pages":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"title":{"type":"string","description":"Title, or empty without access."},"spaceKey":{"type":"string","description":"Key of the page's space, or empty without access."},"kind":{"type":"string","description":"Kind of the item."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the item in the addresses of the app, or null without access."},"accessible":{"type":"boolean","description":"Whether the caller can open the page."},"inTrash":{"type":"boolean","description":"Whether the page is in the trash. Then only the title is given, as `In trash`."}},"required":["title","spaceKey","kind","number","accessible","inTrash"],"additionalProperties":false,"description":"A linked page."},"description":"Linked pages by ID."},"topics":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"title":{"type":"string","description":"Title of the running topic."},"status":{"type":"string","description":"Whether the topic is still open. New values can be added in later versions; handle unknown values.","x-extensible-enum":["open","closed"]}},"required":["title","status"],"additionalProperties":false,"description":"A running topic."},"description":"Running topics that topic updates and decisions in the document refer to, by ID, as far as the caller may see them."},"tooLargeImages":{"type":"array","items":{"type":"string","format":"uuid","description":"ID of an attachment."},"description":"Images in the document with more than 100 megapixels, as far as the caller may see them. They have no smaller version and are shown as a file that opens in full size."}},"required":["people","pages","topics","tooLargeImages"],"additionalProperties":false,"description":"What mentions and page links in the document point to, as far as the caller may see it."}},"required":["diff","before","after","references"],"additionalProperties":false,"description":"A comparison of two versions."},"example":{"diff":{"title":null,"blocks":[],"changes":0},"before":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"after":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"references":{"people":{},"pages":{},"topics":{},"tooLargeImages":[]}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `versionNotFound`: The version does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"versionNotFound":{"value":{"type":"urn:lunedo:problem:versionNotFound","title":"The version does not exist","status":404,"code":"versionNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/pages/{pageId}/content":{"get":{"operationId":"items.content","summary":"Get the content of a page","description":"Returns the content readers see as ProseMirror JSON: the published version in publish mode, the current content in live mode. Open comments on text of that content carry their mark, also when they were made after the version was published. With it come the names of mentioned people and the titles of linked pages the caller may see. Editors get the draft from the draft endpoint.\n\nRequires the permission `item.view` on the item in `pageId`.","tags":["Pages"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The content.","content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"ID of the page."},"title":{"type":"string","description":"Title of the page as readers see it."},"version":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the version readers see, or null when the page has no version yet."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"schemaVersion":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Version of the editor schema the document follows."},"revision":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the stored state; it rises with every save."},"updatedAt":{"type":"string","format":"date-time","description":"When the content was last stored. ISO 8601 timestamp in UTC."},"updatedBy":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Account that stored the content last, or null."},"references":{"type":"object","properties":{"people":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","description":"Name of the person."},"description":"Names of mentioned people the caller may see, by account ID."},"pictures":{"description":"Profile pictures of the people in `people` that have one, by account ID. The picture is at `/api/v1/accounts/{accountId}/picture`.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","description":"Version of the profile picture."}},"pages":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"title":{"type":"string","description":"Title, or empty without access."},"spaceKey":{"type":"string","description":"Key of the page's space, or empty without access."},"kind":{"type":"string","description":"Kind of the item."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the item in the addresses of the app, or null without access."},"accessible":{"type":"boolean","description":"Whether the caller can open the page."},"inTrash":{"type":"boolean","description":"Whether the page is in the trash. Then only the title is given, as `In trash`."}},"required":["title","spaceKey","kind","number","accessible","inTrash"],"additionalProperties":false,"description":"A linked page."},"description":"Linked pages by ID."},"topics":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"title":{"type":"string","description":"Title of the running topic."},"status":{"type":"string","description":"Whether the topic is still open. New values can be added in later versions; handle unknown values.","x-extensible-enum":["open","closed"]}},"required":["title","status"],"additionalProperties":false,"description":"A running topic."},"description":"Running topics that topic updates and decisions in the document refer to, by ID, as far as the caller may see them."},"tooLargeImages":{"type":"array","items":{"type":"string","format":"uuid","description":"ID of an attachment."},"description":"Images in the document with more than 100 megapixels, as far as the caller may see them. They have no smaller version and are shown as a file that opens in full size."}},"required":["people","pages","topics","tooLargeImages"],"additionalProperties":false,"description":"What mentions and page links in the document point to, as far as the caller may see it."}},"required":["itemId","title","version","document","schemaVersion","revision","updatedAt","updatedBy","references"],"additionalProperties":false,"description":"The stored content of a page."},"example":{"itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","title":"VPN access for remote staff","version":7,"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"schemaVersion":4,"revision":4,"updatedAt":"2026-10-05T08:10:00.000Z","updatedBy":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","references":{"people":{},"pages":{},"topics":{},"tooLargeImages":[]}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"put":{"operationId":"items.replace","summary":"Replace the content of a page","description":"Stores new content. It must follow the editor schema. The change is merged into the collaborative document, so people editing the page see it at once. In publish mode it changes the draft; publish it to show it to readers.\n\nRequires the permission `item.edit` on the item in `pageId`.","tags":["Pages"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"}},"required":["document"],"additionalProperties":false,"description":"The new content. It must follow the editor schema."},"example":{"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]}}}}},"responses":{"200":{"description":"The stored content.","content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"ID of the page."},"title":{"type":"string","description":"Title of the page as readers see it."},"version":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the version readers see, or null when the page has no version yet."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"schemaVersion":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Version of the editor schema the document follows."},"revision":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the stored state; it rises with every save."},"updatedAt":{"type":"string","format":"date-time","description":"When the content was last stored. ISO 8601 timestamp in UTC."},"updatedBy":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Account that stored the content last, or null."},"references":{"type":"object","properties":{"people":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","description":"Name of the person."},"description":"Names of mentioned people the caller may see, by account ID."},"pictures":{"description":"Profile pictures of the people in `people` that have one, by account ID. The picture is at `/api/v1/accounts/{accountId}/picture`.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","description":"Version of the profile picture."}},"pages":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"title":{"type":"string","description":"Title, or empty without access."},"spaceKey":{"type":"string","description":"Key of the page's space, or empty without access."},"kind":{"type":"string","description":"Kind of the item."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the item in the addresses of the app, or null without access."},"accessible":{"type":"boolean","description":"Whether the caller can open the page."},"inTrash":{"type":"boolean","description":"Whether the page is in the trash. Then only the title is given, as `In trash`."}},"required":["title","spaceKey","kind","number","accessible","inTrash"],"additionalProperties":false,"description":"A linked page."},"description":"Linked pages by ID."},"topics":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"title":{"type":"string","description":"Title of the running topic."},"status":{"type":"string","description":"Whether the topic is still open. New values can be added in later versions; handle unknown values.","x-extensible-enum":["open","closed"]}},"required":["title","status"],"additionalProperties":false,"description":"A running topic."},"description":"Running topics that topic updates and decisions in the document refer to, by ID, as far as the caller may see them."},"tooLargeImages":{"type":"array","items":{"type":"string","format":"uuid","description":"ID of an attachment."},"description":"Images in the document with more than 100 megapixels, as far as the caller may see them. They have no smaller version and are shown as a file that opens in full size."}},"required":["people","pages","topics","tooLargeImages"],"additionalProperties":false,"description":"What mentions and page links in the document point to, as far as the caller may see it."}},"required":["itemId","title","version","document","schemaVersion","revision","updatedAt","updatedBy","references"],"additionalProperties":false,"description":"The stored content of a page."},"example":{"itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","title":"VPN access for remote staff","version":7,"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"schemaVersion":4,"revision":4,"updatedAt":"2026-10-05T08:10:00.000Z","updatedBy":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","references":{"people":{},"pages":{},"topics":{},"tooLargeImages":[]}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidDocument`: The document does not match the editor schema. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidDocument":{"value":{"type":"urn:lunedo:problem:invalidDocument","title":"The document does not match the editor schema","status":400,"code":"invalidDocument"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/pages/{pageId}/content-language":{"put":{"operationId":"items.setContentLanguage","summary":"Set the content language of a page","description":"Sets the language search uses to match the words of the page, or clears it so the page uses the content language of its space.\n\nRequires the permission `item.edit` on the item in `pageId`.","tags":["Pages"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"language":{"anyOf":[{"type":"string","enum":["ar","ca","da","de","el","en","es","eu","fi","fr","ga","hi","hu","hy","id","it","lt","nb","ne","nl","pt","ro","ru","sr","sv","ta","tr","yi","other"]},{"type":"null"}],"description":"The language, or null to use the language of the space."}},"required":["language"],"additionalProperties":false,"description":"The content language of a page."},"example":{"language":"de"}}}},"responses":{"200":{"description":"The page.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the item."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app, unique in the instance. It never changes and is never reused."},"spaceId":{"type":"string","format":"uuid","description":"Space of the item."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Parent item, or null at the root of the tree."},"kind":{"type":"string","description":"`page`, `folder`, `link`, `blogPost`, `meetingSeries`, `meetingTopic` or `whiteboard`. Blog posts and topics are not part of the tree; they appear in the blog and the meetings of their space. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title. Empty for a link to content the caller cannot read."},"description":{"type":"string","description":"Short description of a folder."},"width":{"type":"string","enum":["fixed","full"],"description":"Page width: `fixed` or `full`."},"numberHeadings":{"type":"boolean","description":"Whether the headings of the page are numbered in the page, in print and in Word."},"mode":{"type":"string","enum":["publish","live"],"description":"Editing mode of a page: `publish` (readers see the last published version while editors work on a draft) or `live` (readers see every change at once). Folders and links are always `live`."},"published":{"type":"boolean","description":"Whether readers can see the page. False for a page in publish mode that was never published; only editors see it."},"archived":{"type":"boolean","description":"Whether the item is archived. Archived items are read-only."},"position":{"type":"string","description":"Sort key among the siblings. Items sort by it in binary order."},"hasChildren":{"type":"boolean","description":"Whether the item has children."},"viewRestriction":{"type":"string","enum":["none","own","inherited"],"description":"Whether only an access list may view the item: set on the item itself, on a page above, or not at all."},"editRestricted":{"type":"boolean","description":"Whether only an access list may edit the item."},"link":{"anyOf":[{"type":"object","properties":{"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Linked page, folder or whiteboard, or null for an address or when the caller cannot read it."},"url":{"description":"Linked `http` or `https` address, or null.","type":["string","null"]},"accessible":{"type":"boolean","description":"Whether the caller can open the target. If not, the title is empty."},"inTrash":{"type":"boolean","description":"Whether the target is in the trash. Only true for callers who could read it before."},"target":{"anyOf":[{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"Space of the target."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the target in the addresses of the app."},"spaceKey":{"type":"string","description":"Key of that space."},"kind":{"type":"string","description":"Kind of the target. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title of the target."}},"required":["spaceId","number","spaceKey","kind","title"],"additionalProperties":false},{"type":"null"}],"description":"The linked page, folder or whiteboard, or null."}},"required":["itemId","url","accessible","inTrash","target"],"additionalProperties":false,"description":"Where a link in the page tree points."},{"type":"null"}],"description":"Target of a link, or null for pages and folders."},"creatorId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Account that created the item, or null."},"contentLanguage":{"anyOf":[{"type":"string","description":"Content language as an ISO 639-1 code, or `other` for a language without its own word matching. Words are then matched as written. New values can be added in later versions; handle unknown values.","x-extensible-enum":["ar","ca","da","de","el","en","es","eu","fi","fr","ga","hi","hu","hy","id","it","lt","nb","ne","nl","pt","ro","ru","sr","sv","ta","tr","yi","other"]},{"type":"null"}],"description":"Language of the page content for search, or null to use the language of the space."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Type of an article in a knowledge base, or null for other items and articles without a type."},"translationOf":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Original article of a translation in a knowledge base, or null. A translation is listed below its original; `contentLanguage` is its language."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of the item, or null. The owner stays set when the person leaves; `owner.active` in the item details says whether the item has an active owner."},"status":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the status value."},"builtIn":{"anyOf":[{"type":"string","x-extensible-enum":["roughDraft","inProgress","readyForReview","verified"]},{"type":"null"}],"description":"Which default value this is, or null for a value a space admin added. Clients show the translated name of a default value unless `name` is set. New values can be added in later versions; handle unknown values."},"name":{"description":"Name set by a space admin, or null to show the default name.","type":["string","null"]},"color":{"type":"string","enum":["neutral","accent","info","success","warning","danger"],"description":"Color of the status: `neutral`, `accent`, `info`, `success`, `warning` or `danger`."}},"required":["id","builtIn","name","color"],"additionalProperties":false,"description":"A page status."},{"type":"null"}],"description":"Status of a page, or null when it has none or page status is turned off in the space."},"createdAt":{"type":"string","format":"date-time","description":"When the item was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the item last changed in the tree. ISO 8601 timestamp in UTC."},"contentUpdatedAt":{"type":"string","format":"date-time","description":"When the content of the page last changed. ISO 8601 timestamp in UTC."}},"required":["id","number","spaceId","parentId","kind","title","description","width","numberHeadings","mode","published","archived","position","hasChildren","viewRestriction","editRestricted","link","creatorId","contentLanguage","articleType","translationOf","ownerId","status","createdAt","updatedAt","contentUpdatedAt"],"additionalProperties":false,"description":"An item of the page tree."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","parentId":null,"kind":"page","title":"VPN access for remote staff","description":"","width":"fixed","numberHeadings":false,"mode":"publish","published":true,"archived":false,"position":"a1","hasChildren":false,"viewRestriction":"none","editRestricted":false,"link":null,"creatorId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","ownerId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","contentLanguage":"de","articleType":null,"translationOf":null,"status":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","builtIn":"verified","name":null,"color":"success"},"createdAt":"2026-10-05T08:00:00.000Z","updatedAt":"2026-10-05T08:00:00.000Z","contentUpdatedAt":"2026-10-05T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/pages/{pageId}/diagrams/{blockId}":{"get":{"operationId":"diagrams.referenced","summary":"Get the current image of a draw.io diagram","description":"Returns what readers of the page currently see of one of its draw.io diagrams: the title and address of the page and the attachment that holds the image. Other pages show a diagram of this page through it, so they always show its current version. Pages the caller may not see are not found.\n\nRequires the permission `item.view` on the item in `pageId`.","tags":["Diagrams"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page or blog post.","schema":{"type":"string","format":"uuid"}},{"name":"blockId","in":"path","required":true,"description":"ID of the diagram block in the page.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The page and the image of the diagram.","content":{"application/json":{"schema":{"type":"object","properties":{"pageId":{"type":"string","format":"uuid","description":"ID of the page or blog post that holds the diagram."},"title":{"type":"string","description":"Title of the page as readers see it."},"path":{"type":"string","description":"Address of the page in the web interface."},"found":{"type":"boolean","description":"Whether the page still holds the diagram."},"previewId":{"anyOf":[{"type":"string","format":"uuid","description":"ID of the attachment that holds the image."},{"type":"null"}],"description":"ID of the attachment that holds the image, or null while the diagram has none."},"previewVersion":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Version of the attachment that readers see, or null while the diagram has no image."}},"required":["pageId","title","path","found","previewId","previewVersion"],"additionalProperties":false,"description":"The diagram."},"example":{"pageId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","title":"Network","path":"/spaces/NET/pages/1020/network","found":true,"previewId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a23","previewVersion":3}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/pages/{pageId}/diagrams/{blockId}/drawio":{"put":{"operationId":"diagrams.drawio","summary":"Store the file of a draw.io diagram","description":"Checks the draw.io file of a diagram block and stores it as a new version of the attachment `drawio-<block ID>.drawio` of the page. Compressed pages are stored uncompressed; scripts, event handlers and links other than web, mail and page links are removed. Point the block to the returned attachment and version; older versions of the page keep showing the diagram they had.\n\nRequires the permission `item.edit` on the item in `pageId`.","tags":["Diagrams"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page or blog post.","schema":{"type":"string","format":"uuid"}},{"name":"blockId","in":"path","required":true,"description":"ID of the diagram block in the page.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"description":"The draw.io file (`mxfile` or `mxGraphModel` XML), up to 4 MB, 50,000 elements and 300,000 attributes.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"Where the file is stored and the text of the diagram.","content":{"application/json":{"schema":{"type":"object","properties":{"sourceId":{"type":"string","format":"uuid","description":"ID of the attachment that holds the file."},"sourceVersion":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Version of the attachment."},"text":{"type":"string","description":"Text of the shapes and connectors, for the block and for search."}},"required":["sourceId","sourceVersion","text"],"additionalProperties":false,"description":"The stored file."},"example":{"sourceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a22","sourceVersion":2,"text":"Core switch"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidDiagram`: The file is not a draw.io diagram Lunedo can store. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidDiagram":{"value":{"type":"urn:lunedo:problem:invalidDiagram","title":"The file is not a draw.io diagram Lunedo can store","status":400,"code":"invalidDiagram"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"408":{"description":"`uploadTimeout`: The upload took too long.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"uploadTimeout":{"value":{"type":"urn:lunedo:problem:uploadTimeout","title":"The upload took too long","status":408,"code":"uploadTimeout"}}}}}},"413":{"description":"`fileTooLarge`: The file is larger than allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"fileTooLarge":{"value":{"type":"urn:lunedo:problem:fileTooLarge","title":"The file is larger than allowed","status":413,"code":"fileTooLarge"}}}}}},"415":{"description":"`unsupportedMediaType`: The request body has an unsupported type.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unsupportedMediaType":{"value":{"type":"urn:lunedo:problem:unsupportedMediaType","title":"The request body has an unsupported type","status":415,"code":"unsupportedMediaType"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`busy`: The server is busy. `maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"busy":{"value":{"type":"urn:lunedo:problem:busy","title":"The server is busy","status":503,"code":"busy"}},"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}},"507":{"description":"`storageFull`: Storage is almost full.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"storageFull":{"value":{"type":"urn:lunedo:problem:storageFull","title":"Storage is almost full","status":507,"code":"storageFull"}}}}}}}}},"/api/v1/pages/{pageId}/diagrams/{blockId}/image":{"put":{"operationId":"diagrams.image","summary":"Store the image of a diagram","description":"Sanitizes the SVG image of a draw.io, Mermaid or PlantUML block and stores it as a new version of the attachment `<type>-<block ID>.svg` of the page. Readers, search results, exports and the print view show this image. Scripts, links, external resources and unknown elements are removed; labels in draw.io diagrams keep simple formatting. Images may be at most 20,000 pixels wide and high, and 10 MB for draw.io or 2 MB for Mermaid and PlantUML.\n\nRequires the permission `item.edit` on the item in `pageId`.","tags":["Diagrams"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page or blog post.","schema":{"type":"string","format":"uuid"}},{"name":"blockId","in":"path","required":true,"description":"ID of the diagram block in the page.","schema":{"type":"string","format":"uuid"}},{"name":"type","in":"query","required":true,"description":"Kind of diagram block: `drawio`, `mermaid` or `plantuml`. It names the attachment and sets the size limit. New values can be added in later versions; handle unknown values.","schema":{"type":"string","x-extensible-enum":["drawio","mermaid","plantuml"]}}],"requestBody":{"required":true,"description":"The SVG image.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"Where the image is stored and the text it shows.","content":{"application/json":{"schema":{"type":"object","properties":{"previewId":{"type":"string","format":"uuid","description":"ID of the attachment that holds the image."},"previewVersion":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Version of the attachment."},"text":{"type":"string","description":"Text shown in the image, for the block and for search."}},"required":["previewId","previewVersion","text"],"additionalProperties":false,"description":"The stored image."},"example":{"previewId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a23","previewVersion":2,"text":"Router\nSwitch"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidDrawingImage`: The image of the drawing is not a valid SVG image. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidDrawingImage":{"value":{"type":"urn:lunedo:problem:invalidDrawingImage","title":"The image of the drawing is not a valid SVG image","status":400,"code":"invalidDrawingImage"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"408":{"description":"`uploadTimeout`: The upload took too long.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"uploadTimeout":{"value":{"type":"urn:lunedo:problem:uploadTimeout","title":"The upload took too long","status":408,"code":"uploadTimeout"}}}}}},"413":{"description":"`fileTooLarge`: The file is larger than allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"fileTooLarge":{"value":{"type":"urn:lunedo:problem:fileTooLarge","title":"The file is larger than allowed","status":413,"code":"fileTooLarge"}}}}}},"415":{"description":"`unsupportedMediaType`: The request body has an unsupported type.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unsupportedMediaType":{"value":{"type":"urn:lunedo:problem:unsupportedMediaType","title":"The request body has an unsupported type","status":415,"code":"unsupportedMediaType"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`busy`: The server is busy. `maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"busy":{"value":{"type":"urn:lunedo:problem:busy","title":"The server is busy","status":503,"code":"busy"}},"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}},"507":{"description":"`storageFull`: Storage is almost full.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"storageFull":{"value":{"type":"urn:lunedo:problem:storageFull","title":"Storage is almost full","status":507,"code":"storageFull"}}}}}}}}},"/api/v1/pages/{pageId}/discarded-drafts":{"get":{"operationId":"versions.discardedDrafts","summary":"List discarded drafts","description":"Lists the drafts discarded or replaced in the last 30 days, newest first.\n\nRequires the permission `item.edit` on the item in `pageId`.","tags":["Versions"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Discarded drafts.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the discarded draft."},"title":{"type":"string","description":"Title of the draft."},"reason":{"type":"string","enum":["discarded","replaced"],"description":"`discarded` by someone, or `replaced` when an older version was restored as the draft."},"discardedAt":{"type":"string","format":"date-time","description":"When the draft was discarded. ISO 8601 timestamp in UTC."},"discardedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when the account no longer exists.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who discarded it."},"expiresAt":{"type":"string","format":"date-time","description":"Until when it can be restored. ISO 8601 timestamp in UTC."},"contributors":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when the account no longer exists.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"Everyone who had changed the draft."}},"required":["id","title","reason","discardedAt","discardedBy","expiresAt","contributors"],"additionalProperties":false,"description":"A discarded draft that can be restored for 30 days."},"description":"Discarded drafts."},"example":[]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/pages/{pageId}/discarded-drafts/{draftId}":{"get":{"operationId":"versions.discardedDraft","summary":"Get a discarded draft","description":"Returns the content of a discarded draft.\n\nRequires the permission `item.edit` on the item in `pageId`.","tags":["Versions"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}},{"name":"draftId","in":"path","required":true,"description":"ID of the discarded draft.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The discarded draft.","content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","description":"Title of the draft."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"references":{"type":"object","properties":{"people":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","description":"Name of the person."},"description":"Names of mentioned people the caller may see, by account ID."},"pictures":{"description":"Profile pictures of the people in `people` that have one, by account ID. The picture is at `/api/v1/accounts/{accountId}/picture`.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","description":"Version of the profile picture."}},"pages":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"title":{"type":"string","description":"Title, or empty without access."},"spaceKey":{"type":"string","description":"Key of the page's space, or empty without access."},"kind":{"type":"string","description":"Kind of the item."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the item in the addresses of the app, or null without access."},"accessible":{"type":"boolean","description":"Whether the caller can open the page."},"inTrash":{"type":"boolean","description":"Whether the page is in the trash. Then only the title is given, as `In trash`."}},"required":["title","spaceKey","kind","number","accessible","inTrash"],"additionalProperties":false,"description":"A linked page."},"description":"Linked pages by ID."},"topics":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"title":{"type":"string","description":"Title of the running topic."},"status":{"type":"string","description":"Whether the topic is still open. New values can be added in later versions; handle unknown values.","x-extensible-enum":["open","closed"]}},"required":["title","status"],"additionalProperties":false,"description":"A running topic."},"description":"Running topics that topic updates and decisions in the document refer to, by ID, as far as the caller may see them."},"tooLargeImages":{"type":"array","items":{"type":"string","format":"uuid","description":"ID of an attachment."},"description":"Images in the document with more than 100 megapixels, as far as the caller may see them. They have no smaller version and are shown as a file that opens in full size."}},"required":["people","pages","topics","tooLargeImages"],"additionalProperties":false,"description":"What mentions and page links in the document point to, as far as the caller may see it."}},"required":["title","document","references"],"additionalProperties":false,"description":"A discarded draft with its content."},"example":{"title":"VPN access for remote staff","document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"references":{"people":{},"pages":{},"topics":{},"tooLargeImages":[]}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/pages/{pageId}/discarded-drafts/{draftId}/restore":{"post":{"operationId":"versions.restoreDiscarded","summary":"Restore a discarded draft","description":"Makes a discarded draft the draft again. A current draft with changes is kept as a discarded draft itself.\n\nRequires the permission `item.edit` on the item in `pageId`.","tags":["Versions"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}},{"name":"draftId","in":"path","required":true,"description":"ID of the discarded draft.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`discardedDraftNotFound`: The discarded draft does not exist. `notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"discardedDraftNotFound":{"value":{"type":"urn:lunedo:problem:discardedDraftNotFound","title":"The discarded draft does not exist","status":404,"code":"discardedDraftNotFound"}},"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notPublishMode`: The page is not in publish mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notPublishMode":{"value":{"type":"urn:lunedo:problem:notPublishMode","title":"The page is not in publish mode","status":409,"code":"notPublishMode"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/pages/{pageId}/draft":{"get":{"operationId":"versions.draft","summary":"Get the draft of a page","description":"Returns the shared draft that editors work on, with the number of changes since the published version. In live mode the draft is the current content.\n\nRequires the permission `item.edit` on the item in `pageId`.","tags":["Versions"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The draft.","content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","description":"Title of the draft."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"revision":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the stored state of the draft."},"updatedAt":{"type":"string","format":"date-time","description":"When the draft was last stored. ISO 8601 timestamp in UTC."},"hasChanges":{"type":"boolean","description":"Whether the draft differs from the published version."},"changes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Number of changes since the published version, or null when the page was never published."},"basedOn":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The published version, or null."},"contributors":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when the account no longer exists.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"Everyone who changed the draft since the last version."},"references":{"type":"object","properties":{"people":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","description":"Name of the person."},"description":"Names of mentioned people the caller may see, by account ID."},"pictures":{"description":"Profile pictures of the people in `people` that have one, by account ID. The picture is at `/api/v1/accounts/{accountId}/picture`.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","description":"Version of the profile picture."}},"pages":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"title":{"type":"string","description":"Title, or empty without access."},"spaceKey":{"type":"string","description":"Key of the page's space, or empty without access."},"kind":{"type":"string","description":"Kind of the item."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the item in the addresses of the app, or null without access."},"accessible":{"type":"boolean","description":"Whether the caller can open the page."},"inTrash":{"type":"boolean","description":"Whether the page is in the trash. Then only the title is given, as `In trash`."}},"required":["title","spaceKey","kind","number","accessible","inTrash"],"additionalProperties":false,"description":"A linked page."},"description":"Linked pages by ID."},"topics":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"title":{"type":"string","description":"Title of the running topic."},"status":{"type":"string","description":"Whether the topic is still open. New values can be added in later versions; handle unknown values.","x-extensible-enum":["open","closed"]}},"required":["title","status"],"additionalProperties":false,"description":"A running topic."},"description":"Running topics that topic updates and decisions in the document refer to, by ID, as far as the caller may see them."},"tooLargeImages":{"type":"array","items":{"type":"string","format":"uuid","description":"ID of an attachment."},"description":"Images in the document with more than 100 megapixels, as far as the caller may see them. They have no smaller version and are shown as a file that opens in full size."}},"required":["people","pages","topics","tooLargeImages"],"additionalProperties":false,"description":"What mentions and page links in the document point to, as far as the caller may see it."}},"required":["title","document","revision","updatedAt","hasChanges","changes","basedOn","contributors","references"],"additionalProperties":false,"description":"The shared draft of a page."},"example":{"title":"VPN access for remote staff","document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"revision":18,"updatedAt":"2026-10-07T09:12:00.000Z","hasChanges":true,"changes":3,"basedOn":7,"contributors":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"}],"references":{"people":{},"pages":{},"topics":{},"tooLargeImages":[]}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/pages/{pageId}/draft/discard":{"post":{"operationId":"versions.discard","summary":"Discard the draft","description":"Resets the draft to the published version for everyone editing. The discarded draft can be restored for 30 days.\n\nRequires the permission `item.edit` on the item in `pageId`.","tags":["Versions"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The discarded draft, for undo.","content":{"application/json":{"schema":{"type":"object","properties":{"discardedDraftId":{"type":"string","format":"uuid","description":"ID of the discarded draft."}},"required":["discardedDraftId"],"additionalProperties":false,"description":"The discarded draft."},"example":{"discardedDraftId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a50"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`nothingToDiscard`: The draft has no changes to discard.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"nothingToDiscard":{"value":{"type":"urn:lunedo:problem:nothingToDiscard","title":"The draft has no changes to discard","status":409,"code":"nothingToDiscard"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/pages/{pageId}/drawings/{blockId}/preview":{"put":{"operationId":"whiteboards.drawingPreview","summary":"Store the image of a drawing","description":"Sanitizes the SVG image of a drawing block and stores it as a new version of the attachment `drawing-<block ID>.svg` of the page. Readers, exports and the print view show this image.\n\nRequires the permission `item.edit` on the item in `pageId`.","tags":["Whiteboards"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page or blog post.","schema":{"type":"string","format":"uuid"}},{"name":"blockId","in":"path","required":true,"description":"ID of the drawing block in the page.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"description":"The SVG image, up to 5 MB. Scripts, links, external resources and foreign content are removed.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"Where the image is stored.","content":{"application/json":{"schema":{"type":"object","properties":{"previewId":{"type":"string","format":"uuid","description":"ID of the attachment that holds the image."},"previewVersion":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Version of the attachment."}},"required":["previewId","previewVersion"],"additionalProperties":false,"description":"The stored image."},"example":{"previewId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a23","previewVersion":2}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidDrawingImage`: The image of the drawing is not a valid SVG image. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidDrawingImage":{"value":{"type":"urn:lunedo:problem:invalidDrawingImage","title":"The image of the drawing is not a valid SVG image","status":400,"code":"invalidDrawingImage"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"408":{"description":"`uploadTimeout`: The upload took too long.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"uploadTimeout":{"value":{"type":"urn:lunedo:problem:uploadTimeout","title":"The upload took too long","status":408,"code":"uploadTimeout"}}}}}},"413":{"description":"`fileTooLarge`: The file is larger than allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"fileTooLarge":{"value":{"type":"urn:lunedo:problem:fileTooLarge","title":"The file is larger than allowed","status":413,"code":"fileTooLarge"}}}}}},"415":{"description":"`unsupportedMediaType`: The request body has an unsupported type.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unsupportedMediaType":{"value":{"type":"urn:lunedo:problem:unsupportedMediaType","title":"The request body has an unsupported type","status":415,"code":"unsupportedMediaType"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`busy`: The server is busy. `maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"busy":{"value":{"type":"urn:lunedo:problem:busy","title":"The server is busy","status":503,"code":"busy"}},"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}},"507":{"description":"`storageFull`: Storage is almost full.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"storageFull":{"value":{"type":"urn:lunedo:problem:storageFull","title":"Storage is almost full","status":507,"code":"storageFull"}}}}}}}}},"/api/v1/pages/{pageId}/drawings/{blockId}/scene":{"put":{"operationId":"whiteboards.drawingScene","summary":"Store the scene of a drawing","description":"Validates the scene of a drawing block and stores it as a new version of the attachment `drawing-<block ID>.excalidraw` of the page. Point the block to the returned attachment and version; older versions of the page keep showing the drawing they had.\n\nRequires the permission `item.edit` on the item in `pageId`.","tags":["Whiteboards"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page or blog post.","schema":{"type":"string","format":"uuid"}},{"name":"blockId","in":"path","required":true,"description":"ID of the drawing block in the page.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"description":"The scene as JSON, up to 8 MB, in the same form as the scene of a whiteboard.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"Where the scene is stored and the text of the drawing.","content":{"application/json":{"schema":{"type":"object","properties":{"sceneId":{"type":"string","format":"uuid","description":"ID of the attachment that holds the scene."},"sceneVersion":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Version of the attachment."},"text":{"type":"string","description":"Text of the drawing, for the block and for search."}},"required":["sceneId","sceneVersion","text"],"additionalProperties":false,"description":"The stored scene."},"example":{"sceneId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a22","sceneVersion":2,"text":"Server room"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidScene`: The drawing contains something Lunedo cannot store.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidScene":{"value":{"type":"urn:lunedo:problem:invalidScene","title":"The drawing contains something Lunedo cannot store","status":400,"code":"invalidScene"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"413":{"description":"`fileTooLarge`: The file is larger than allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"fileTooLarge":{"value":{"type":"urn:lunedo:problem:fileTooLarge","title":"The file is larger than allowed","status":413,"code":"fileTooLarge"}}}}}},"415":{"description":"`unsupportedMediaType`: The request body has an unsupported type.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unsupportedMediaType":{"value":{"type":"urn:lunedo:problem:unsupportedMediaType","title":"The request body has an unsupported type","status":415,"code":"unsupportedMediaType"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}},"507":{"description":"`storageFull`: Storage is almost full.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"storageFull":{"value":{"type":"urn:lunedo:problem:storageFull","title":"Storage is almost full","status":507,"code":"storageFull"}}}}}}}}},"/api/v1/pages/{pageId}/editors":{"get":{"operationId":"items.editors","summary":"List the people editing a page now","description":"Lists the people who have the page open in the editor at this moment. Readers of the page are not listed. The list changes with an `editing` event in the space stream.\n\nRequires the permission `item.view` on the item in `pageId`.","tags":["Pages"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The people editing the page.","content":{"application/json":{"schema":{"type":"object","properties":{"editors":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when the caller may not see it.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null when there is none.","type":["string","null"]}},"required":["id","name","pictureRef"],"additionalProperties":false,"description":"A person editing the page."},"description":"People with the page open in the editor."}},"required":["editors"],"additionalProperties":false,"description":"Who is editing the page now."},"example":{"editors":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger","pictureRef":null}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/pages/{pageId}/export":{"get":{"operationId":"exports.page","summary":"Export a page","description":"Sends the page as readers see it: the published version in publish mode. Modules such as child page lists and reports are rendered with your permissions; content you cannot read is left out. Private notes and the history are not exported; open comments only in `print`, `pdf` and `docx` when asked for. Links to other pages and to attachments point to Lunedo, except the attachments inside a ZIP. Images in `pdf` and `docx` are embedded when you may read them. Without the render container, `pdf` answers with `renderUnavailable`; people can still print the `print` format to PDF in their browser.\n\nRequires the permission `item.export` on the item in `pageId`.","tags":["Exports"],"x-lunedo-permission":{"action":"item.export","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}},{"name":"format","in":"query","required":true,"description":"`markdown` for one Markdown file, `html` for one HTML file with inline styles that can be read offline, `zip` for both together with the attachments of the page. `print` for print-ready HTML with page breaks, header, footer and contents, laid out into sheets by a pagination library such as Vivliostyle. `pdf` for a PDF file, which needs the optional render container. `docx` for a Word document.","schema":{"type":"string","enum":["markdown","html","zip","print","pdf","docx"]}},{"name":"attachments","in":"query","required":false,"description":"For `print`, `pdf` and `docx`: `true` (the default) adds an appendix that lists the attachments of the page.","schema":{"type":"string","enum":["true","false"]}},{"name":"comments","in":"query","required":false,"description":"For `print`, `pdf` and `docx`: `true` adds the open comments after the page. Off by default.","schema":{"type":"string","enum":["true","false"]}},{"name":"contents","in":"query","required":false,"description":"For `print`, `pdf` and `docx`: `true` (the default) adds a table of contents.","schema":{"type":"string","enum":["true","false"]}},{"name":"paper","in":"query","required":false,"description":"Paper size for `print`, `pdf` and `docx`; `a4` by default.","schema":{"type":"string","enum":["a4","letter"]}},{"name":"orientation","in":"query","required":false,"description":"Orientation for `print`, `pdf` and `docx`; `portrait` by default.","schema":{"type":"string","enum":["portrait","landscape"]}}],"responses":{"200":{"description":"The page as a Markdown file, an HTML file, a ZIP archive, a PDF file or a Word document.","content":{"text/markdown":{"schema":{"type":"string"},"example":"# Connect through WireGuard\n"},"application/zip":{"schema":{"type":"string"},"example":"# Connect through WireGuard\n"},"text/html":{"schema":{"type":"string"},"example":"# Connect through WireGuard\n"},"application/pdf":{"schema":{"type":"string"},"example":"# Connect through WireGuard\n"},"application/vnd.openxmlformats-officedocument.wordprocessingml.document":{"schema":{"type":"string"},"example":"# Connect through WireGuard\n"}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`exportDisabled`: Export is turned off for this space. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"exportDisabled":{"value":{"type":"urn:lunedo:problem:exportDisabled","title":"Export is turned off for this space","status":403,"code":"exportDisabled"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`nothingToExport`: There is nothing to export.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"nothingToExport":{"value":{"type":"urn:lunedo:problem:nothingToExport","title":"There is nothing to export","status":409,"code":"nothingToExport"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"502":{"description":"`renderFailed`: The render container could not create the PDF.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"renderFailed":{"value":{"type":"urn:lunedo:problem:renderFailed","title":"The render container could not create the PDF","status":502,"code":"renderFailed"}}}}}},"503":{"description":"`busy`: The server is busy. `renderUnavailable`: Server-side PDF needs the render container.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"busy":{"value":{"type":"urn:lunedo:problem:busy","title":"The server is busy","status":503,"code":"busy"}},"renderUnavailable":{"value":{"type":"urn:lunedo:problem:renderUnavailable","title":"Server-side PDF needs the render container","status":503,"code":"renderUnavailable"}}}}}}}}},"/api/v1/pages/{pageId}/exports":{"post":{"operationId":"exports.exportPages","summary":"Export a page with its subpages","description":"Starts an export of the page and every subpage you can read: by default a ZIP archive with the page tree as folders, each page as Markdown and HTML and the attachments next to their pages; with a format, one print-ready HTML file, PDF file or Word document of all pages. Only space administrators, and organization administrators with access to the space outside confidential spaces, can start it. It is refused when the file store would pass the usage level where large writes are blocked (90 % by default), and stops when the usage reaches the critical level (95 % by default) while it is written. The export runs in the background. When it is ready, you get a notification with the download; only you can open it. The download is deleted 24 hours after it was first downloaded completely, or after 7 days if it is never downloaded. You can run one export at a time and keep up to 5; a new export of the same space or page replaces the earlier one.\n\nRequires the permission `item.exportPages` on the item in `pageId`.","tags":["Exports"],"x-lunedo-permission":{"action":"item.exportPages","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"description":"What to export and how. Without a body, the export is a ZIP with every page as Markdown and HTML.","type":"object","properties":{"format":{"default":"archive","description":"`archive` (the default) for a ZIP with every page as Markdown and HTML, `html` or `markdown` for a ZIP with one of them, `print` for one print-ready HTML file of up to 300 pages, `pdf` for one PDF file, which needs the optional render container, `docx` for one Word document.","type":"string","enum":["archive","html","markdown","print","pdf","docx"]},"attachments":{"default":true,"description":"Adds the attachments: next to their pages in a ZIP, as an appendix that lists them in `print`, `pdf` and `docx`. `archive` always contains them.","type":"boolean"},"comments":{"default":false,"description":"Adds the open comments after each page in `print`, `pdf` and `docx`.","type":"boolean"},"contents":{"default":true,"description":"Adds a table of contents in `print`, `pdf` and `docx`.","type":"boolean"},"paper":{"default":"a4","description":"Paper size for `print`, `pdf` and `docx`.","type":"string","enum":["a4","letter"]},"orientation":{"default":"portrait","description":"Orientation for `print`, `pdf` and `docx`.","type":"string","enum":["portrait","landscape"]}},"additionalProperties":false},"example":{"format":"docx","attachments":true,"comments":false,"contents":true,"paper":"a4","orientation":"portrait"}}}},"responses":{"202":{"description":"The started export.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the export."},"scope":{"type":"string","enum":["space","pages"],"description":"What is exported: `space` for a whole space, `pages` for a page with its subpages."},"format":{"type":"string","enum":["archive","html","markdown","print","pdf","docx","site"],"description":"What the file contains: `archive` a ZIP with every page as Markdown and HTML, `html` or `markdown` a ZIP with one of them, `print` one print-ready HTML file, `pdf` one PDF file, `docx` one Word document, `site` a ZIP with a static website of a public knowledge base."},"options":{"type":"object","properties":{"attachments":{"type":"boolean","description":"Whether the attachments are included or listed."},"comments":{"type":"boolean","description":"Whether open comments are included."},"contents":{"type":"boolean","description":"Whether a table of contents is included."},"paper":{"type":"string","enum":["a4","letter"],"description":"Paper size of `print`, `pdf` and `docx`."},"orientation":{"type":"string","enum":["portrait","landscape"],"description":"Orientation of `print`, `pdf` and `docx`."},"siteUrl":{"description":"Address the static website of `site` is served from, or null when none was given.","type":["string","null"]}},"required":["attachments","comments","contents","paper","orientation","siteUrl"],"additionalProperties":false,"description":"The options the export was started with."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The exported space, or null when it was deleted since."},"rootItemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The exported page for `pages`, or null."},"name":{"type":"string","description":"Name of the space or title of the page when the export was started."},"state":{"type":"string","enum":["queued","running","ready","failed"],"description":"`queued` waits for a worker, `running` is being built, `ready` can be downloaded, `failed` stopped with an error."},"progress":{"type":"object","properties":{"done":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Files written so far."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Files in the export, 0 until known."}},"required":["done","total"],"additionalProperties":false,"description":"Progress of a running export."},"fileName":{"description":"File name of the file once it is ready.","type":["string","null"]},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size of the file in bytes once it is ready."},"errorCode":{"anyOf":[{"type":"string","x-extensible-enum":["exportDisabled","noAccess","tokenRevoked","notEnoughStorage","renderUnavailable","renderFailed","renderTooLarge","tooManyPagesForFile","tooLargeToBuild","notPublic","interrupted","internalError"]},{"type":"null"}],"description":"Why a failed export stopped: export was turned off for the space, the permission to export the space or page was lost, the API token that started it was revoked, the file store ran short of free space while it was written, the render container for PDF is not set up or cannot be reached, it could not create the PDF, the document was larger than the render container accepts, the Word or PDF file would have more pages than the limit, building the file ran out of memory, the knowledge base of a static website is no longer public, the worker was interrupted too often, or an unexpected error. New values can be added in later versions; handle unknown values."},"createdAt":{"type":"string","format":"date-time","description":"When the export was started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the export finished or failed. ISO 8601 timestamp in UTC."},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the download is deleted: 24 hours after its first complete download, at the latest 7 days after it is ready. ISO 8601 timestamp in UTC."}},"required":["id","scope","format","options","spaceId","rootItemId","name","state","progress","fileName","size","errorCode","createdAt","finishedAt","expiresAt"],"additionalProperties":false,"description":"An export of a space or of a page with its subpages, built in the background."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a90","scope":"pages","format":"archive","options":{"attachments":true,"comments":false,"contents":true,"paper":"a4","orientation":"portrait","siteUrl":null},"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","rootItemId":null,"name":"IT Operations","state":"queued","progress":{"done":0,"total":0},"fileName":"IT Operations 2026-10-14.zip","size":18432112,"errorCode":null,"createdAt":"2026-10-14T09:00:00.000Z","finishedAt":"2026-10-14T09:01:12.000Z","expiresAt":"2026-10-21T09:01:12.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `exportDisabled`: Export is turned off for this space. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"exportDisabled":{"value":{"type":"urn:lunedo:problem:exportDisabled","title":"Export is turned off for this space","status":403,"code":"exportDisabled"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`exportRunning`: Another export of yours is still running. `nothingToExport`: There is nothing to export. `tooManyExports`: You keep as many exports as allowed. `tooManyPagesForFile`: Too many pages for a Word or PDF file. `tooManyPagesToPrint`: Too many pages to print in a browser.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"exportRunning":{"value":{"type":"urn:lunedo:problem:exportRunning","title":"Another export of yours is still running","status":409,"code":"exportRunning"}},"nothingToExport":{"value":{"type":"urn:lunedo:problem:nothingToExport","title":"There is nothing to export","status":409,"code":"nothingToExport"}},"tooManyExports":{"value":{"type":"urn:lunedo:problem:tooManyExports","title":"You keep as many exports as allowed","status":409,"code":"tooManyExports"}},"tooManyPagesForFile":{"value":{"type":"urn:lunedo:problem:tooManyPagesForFile","title":"Too many pages for a Word or PDF file","status":409,"code":"tooManyPagesForFile"}},"tooManyPagesToPrint":{"value":{"type":"urn:lunedo:problem:tooManyPagesToPrint","title":"Too many pages to print in a browser","status":409,"code":"tooManyPagesToPrint"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode. `renderUnavailable`: Server-side PDF needs the render container.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}},"renderUnavailable":{"value":{"type":"urn:lunedo:problem:renderUnavailable","title":"Server-side PDF needs the render container","status":503,"code":"renderUnavailable"}}}}}},"507":{"description":"`notEnoughStorage`: Not enough storage for this export.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notEnoughStorage":{"value":{"type":"urn:lunedo:problem:notEnoughStorage","title":"Not enough storage for this export","status":507,"code":"notEnoughStorage"}}}}}}}}},"/api/v1/pages/{pageId}/exports/summary":{"get":{"operationId":"exports.pagesSummary","summary":"Count what an export of a page with its subpages contains","description":"Counts the page and its subpages that you can read, so you can choose a format before you start the export. Browsers print up to `printLimit` pages at once; `serverPdf` tells whether the render container can create PDF files instead.\n\nRequires the permission `item.exportPages` on the item in `pageId`.","tags":["Exports"],"x-lunedo-permission":{"action":"item.exportPages","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The counts.","content":{"application/json":{"schema":{"type":"object","properties":{"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages you can read in the scope."},"blogPosts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Published blog posts you can read; only for a whole space."},"printLimit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Most pages a browser prints at once through the print view."},"fileLimit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Most pages a Word or PDF file can hold; larger exports need an HTML or Markdown archive."},"serverPdf":{"type":"boolean","description":"Whether the render container is set up, so PDF can be created on the server."},"largeWritesPaused":{"type":"boolean","description":"Whether the file store is so full that exports of a space or of a page with its subpages are refused right now."}},"required":["pages","blogPosts","printLimit","fileLimit","serverPdf","largeWritesPaused"],"additionalProperties":false,"description":"What an export of a space or of a page with its subpages contains."},"example":{"pages":412,"blogPosts":31,"printLimit":300,"fileLimit":1000,"serverPdf":false,"largeWritesPaused":false}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`exportDisabled`: Export is turned off for this space. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"exportDisabled":{"value":{"type":"urn:lunedo:problem:exportDisabled","title":"Export is turned off for this space","status":403,"code":"exportDisabled"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`nothingToExport`: There is nothing to export.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"nothingToExport":{"value":{"type":"urn:lunedo:problem:nothingToExport","title":"There is nothing to export","status":409,"code":"nothingToExport"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/pages/{pageId}/give-access/preview":{"post":{"operationId":"pageAccess.givePagePreview","summary":"Preview giving access to a page","description":"Shows how many pages the person or group could then read and edit, how many restricted pages they would still not see, and who gains access. Nothing is changed.\n\nRequires the permission `item.share` on the item in `pageId`.","tags":["Page access"],"x-lunedo-permission":{"action":"item.share","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"holderKind":{"type":"string","enum":["account","group"],"description":"`account` for a person, `group` for a group."},"holderId":{"type":"string","format":"uuid","description":"ID of the account or group."},"level":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"`reader`, `commenter`, `editor`, or `admin` to manage the space."},"scope":{"type":"string","enum":["space","page","pageAndChildren"],"description":"Where: the whole space, this page, or this page with its pages."}},"required":["holderKind","holderId","level","scope"],"additionalProperties":false,"description":"Access to give."},"example":{"holderKind":"account","holderId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","level":"editor","scope":"pageAndChildren"}}}},"responses":{"200":{"description":"The effect.","content":{"application/json":{"schema":{"type":"object","properties":{"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages in the chosen place."},"readable":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages the holder could then read."},"editable":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages the holder could then edit."},"restricted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Restricted pages the holder would still not see."},"alreadyHas":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"]},{"type":"null"}],"description":"Role the person already has in the space."},"impact":{"anyOf":[{"type":"object","properties":{"gaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who get access."},"losing":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who lose access."},"raised":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role rises."},"lowered":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role drops."},"unlisted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of affected people the caller may not see; they are counted but not listed."},"truncated":{"type":"boolean","description":"Whether `changes` lists only the first 100 people."},"changes":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."},"before":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role before the change, or null for no access."},"after":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role after the change, or null for no access."}},"required":["accountId","name","before","after"],"additionalProperties":false,"description":"How the access of one person changes."},"description":"People whose access changes, ordered by name."}},"required":["gaining","losing","raised","lowered","unlisted","truncated","changes"],"additionalProperties":false,"description":"Who gains, loses or changes access."},{"type":"object","properties":{"read":{"type":"object","properties":{"gaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who get access."},"losing":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who lose access."},"raised":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role rises."},"lowered":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role drops."},"unlisted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of affected people the caller may not see; they are counted but not listed."},"truncated":{"type":"boolean","description":"Whether `changes` lists only the first 100 people."},"changes":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."},"before":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role before the change, or null for no access."},"after":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role after the change, or null for no access."}},"required":["accountId","name","before","after"],"additionalProperties":false,"description":"How the access of one person changes."},"description":"People whose access changes, ordered by name."}},"required":["gaining","losing","raised","lowered","unlisted","truncated","changes"],"additionalProperties":false,"description":"Who gains or loses the right to read."},"edit":{"type":"object","properties":{"gaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who get access."},"losing":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who lose access."},"raised":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role rises."},"lowered":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role drops."},"unlisted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of affected people the caller may not see; they are counted but not listed."},"truncated":{"type":"boolean","description":"Whether `changes` lists only the first 100 people."},"changes":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."},"before":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role before the change, or null for no access."},"after":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role after the change, or null for no access."}},"required":["accountId","name","before","after"],"additionalProperties":false,"description":"How the access of one person changes."},"description":"People whose access changes, ordered by name."}},"required":["gaining","losing","raised","lowered","unlisted","truncated","changes"],"additionalProperties":false,"description":"Who gains or loses the right to edit."}},"required":["read","edit"],"additionalProperties":false,"description":"How access to the page would change."}],"description":"Who gains or loses access: for the space, or for read and edit of the page."}},"required":["pages","readable","editable","restricted","alreadyHas","impact"],"additionalProperties":false,"description":"The effect of giving access."},"example":{"pages":34,"readable":31,"editable":31,"restricted":3,"alreadyHas":null,"impact":{"read":{"gaining":1,"losing":0,"raised":0,"lowered":0,"unlisted":0,"truncated":false,"changes":[{"accountId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger","before":null,"after":"reader"}]},"edit":{"gaining":0,"losing":0,"raised":0,"lowered":0,"unlisted":0,"truncated":false,"changes":[]}}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid. `invalidRole`: The role cannot be given here.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidRole":{"value":{"type":"urn:lunedo:problem:invalidRole","title":"The role cannot be given here","status":400,"code":"invalidRole"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`confidentialGuestsBySpaceAdmins`: Only space administrators give guests access to a confidential space. `csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `ownShare`: Nobody changes access they hold themselves. `shareBeyondOwnAccess`: A share cannot reach further than your own access.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"confidentialGuestsBySpaceAdmins":{"value":{"type":"urn:lunedo:problem:confidentialGuestsBySpaceAdmins","title":"Only space administrators give guests access to a confidential space","status":403,"code":"confidentialGuestsBySpaceAdmins"}},"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"ownShare":{"value":{"type":"urn:lunedo:problem:ownShare","title":"Nobody changes access they hold themselves","status":403,"code":"ownShare"}},"shareBeyondOwnAccess":{"value":{"type":"urn:lunedo:problem:shareBeyondOwnAccess","title":"A share cannot reach further than your own access","status":403,"code":"shareBeyondOwnAccess"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/pages/{pageId}/inclusion":{"get":{"operationId":"reports.inclusion","summary":"Get content included in a page","description":"Returns the published content of another page, or its excerpt, as an include block of the page shows it, with the caller's permissions. For people who can edit the page, it also says whether some of its readers cannot read the included page. A page that was not part of a Confluence import is found by its space key and title once it is imported into the organization. A page the caller cannot read answers like a page that does not exist.\n\nRequires the permission `item.view` on the item in `pageId`.","tags":["Reports"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page that shows the block.","schema":{"type":"string","format":"uuid"}},{"name":"targetId","in":"query","required":false,"description":"The page to include.","schema":{"type":"string","format":"uuid"}},{"name":"sourceSpace","in":"query","required":false,"description":"Confluence space key of an included page that was not part of the import.","schema":{"type":"string","minLength":1,"maxLength":255}},{"name":"sourceTitle","in":"query","required":false,"description":"Confluence title of an included page that was not part of the import.","schema":{"type":"string","minLength":1,"maxLength":255}},{"name":"excerpt","in":"query","required":false,"description":"`true` gives only the excerpt of the page.","schema":{"default":"false","type":"string","enum":["true","false"]}},{"name":"name","in":"query","required":false,"description":"Name of the excerpt. Leave it out for the first excerpt.","schema":{"type":"string","minLength":1,"maxLength":100}}],"responses":{"200":{"description":"The included content.","content":{"application/json":{"schema":{"type":"object","properties":{"state":{"type":"string","description":"`visible` with the content, or `noExcerpt` when the page has no excerpt of that name. New values can be added in later versions; handle unknown values.","x-extensible-enum":["visible","noExcerpt"]},"page":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the included page."},"title":{"type":"string","description":"Title of the included page."},"path":{"type":"string","description":"Path of the included page in the web interface."},"spaceId":{"type":"string","format":"uuid","description":"Space of the included page."}},"required":["id","title","path","spaceId"],"additionalProperties":false,"description":"The included page."},"document":{"anyOf":[{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},{"type":"null"}],"description":"The published content, or only its excerpt. Null without excerpt."},"references":{"type":"object","properties":{"people":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","description":"Name of the person."},"description":"Names of mentioned people the caller may see, by account ID."},"pictures":{"description":"Profile pictures of the people in `people` that have one, by account ID. The picture is at `/api/v1/accounts/{accountId}/picture`.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","description":"Version of the profile picture."}},"pages":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"title":{"type":"string","description":"Title, or empty without access."},"spaceKey":{"type":"string","description":"Key of the page's space, or empty without access."},"kind":{"type":"string","description":"Kind of the item."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the item in the addresses of the app, or null without access."},"accessible":{"type":"boolean","description":"Whether the caller can open the page."},"inTrash":{"type":"boolean","description":"Whether the page is in the trash. Then only the title is given, as `In trash`."}},"required":["title","spaceKey","kind","number","accessible","inTrash"],"additionalProperties":false,"description":"A linked page."},"description":"Linked pages by ID."},"topics":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"title":{"type":"string","description":"Title of the running topic."},"status":{"type":"string","description":"Whether the topic is still open. New values can be added in later versions; handle unknown values.","x-extensible-enum":["open","closed"]}},"required":["title","status"],"additionalProperties":false,"description":"A running topic."},"description":"Running topics that topic updates and decisions in the document refer to, by ID, as far as the caller may see them."},"tooLargeImages":{"type":"array","items":{"type":"string","format":"uuid","description":"ID of an attachment."},"description":"Images in the document with more than 100 megapixels, as far as the caller may see them. They have no smaller version and are shown as a file that opens in full size."}},"required":["people","pages","topics","tooLargeImages"],"additionalProperties":false,"description":"What mentions and page links in the document point to, as far as the caller may see it."},"hiddenFromSomeReaders":{"type":"boolean","description":"True when some people who can read the including page cannot read the included page and see nothing in its place. Only checked for people who can edit the including page; false for everyone else."}},"required":["state","page","document","references","hiddenFromSomeReaders"],"additionalProperties":false,"description":"Content included from another page."},"example":{"state":"visible","page":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5c11","title":"VPN access for remote staff","path":"/spaces/ITOPS/pages/1042/vpn-access-for-remote-staff","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10"},"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"references":{"people":{},"pages":{},"topics":{},"tooLargeImages":[]},"hiddenFromSomeReaders":false}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/pages/{pageId}/labels":{"get":{"operationId":"items.labels","summary":"List the labels of a page","description":"Returns the labels of the page, sorted.\n\nRequires the permission `item.view` on the item in `pageId`.","tags":["Pages"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The labels.","content":{"application/json":{"schema":{"type":"array","items":{"type":"string","description":"A label, lowercase, up to 100 characters."},"description":"Labels, sorted."},"example":["runbook","vpn"]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"items.addLabel","summary":"Add a label to a page","description":"Adds a label. Labels are stored in lowercase with dashes instead of spaces.\n\nRequires the permission `item.edit` on the item in `pageId`.","tags":["Pages"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","maxLength":200,"description":"The label; it is stored in lowercase with dashes for spaces."}},"required":["label"],"additionalProperties":false,"description":"A label."},"example":{"label":"Runbook"}}}},"responses":{"200":{"description":"The labels after the change.","content":{"application/json":{"schema":{"type":"array","items":{"type":"string","description":"A label, lowercase, up to 100 characters."},"description":"Labels, sorted."},"example":["runbook","vpn"]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidLabel`: The label is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidLabel":{"value":{"type":"urn:lunedo:problem:invalidLabel","title":"The label is not valid","status":400,"code":"invalidLabel"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`tooManyLabels`: The page has too many labels.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"tooManyLabels":{"value":{"type":"urn:lunedo:problem:tooManyLabels","title":"The page has too many labels","status":409,"code":"tooManyLabels"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/pages/{pageId}/labels/{label}":{"delete":{"operationId":"items.removeLabel","summary":"Remove a label from a page","description":"Removes the label from the page.\n\nRequires the permission `item.edit` on the item in `pageId`.","tags":["Pages"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}},{"name":"label","in":"path","required":true,"description":"The label.","schema":{"type":"string","maxLength":200}}],"responses":{"200":{"description":"The labels after the change.","content":{"application/json":{"schema":{"type":"array","items":{"type":"string","description":"A label, lowercase, up to 100 characters."},"description":"Labels, sorted."},"example":["vpn"]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/pages/{pageId}/links/follow":{"post":{"operationId":"items.follow","summary":"Follow a link to a page by title","description":"Opens the page with the title in the space, or creates it when it does not exist yet and the caller may edit there. When the caller may edit this page, its links by title become links by ID.\n\nRequires the permission `item.view` on the item in `pageId`.","tags":["Pages"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"Space the link points to."},"title":{"type":"string","maxLength":255,"description":"Title of the page the link points to."}},"required":["spaceId","title"],"additionalProperties":false,"description":"A link by title."},"example":{"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","title":"Device naming"}}}},"responses":{"200":{"description":"The page the link leads to.","content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"The page the link leads to."},"created":{"type":"boolean","description":"Whether the page was created now."}},"required":["itemId","created"],"additionalProperties":false,"description":"Where the link leads."},"example":{"itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","created":true}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidTitle`: The title is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidTitle":{"value":{"type":"urn:lunedo:problem:invalidTitle","title":"The title is not valid","status":400,"code":"invalidTitle"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/pages/{pageId}/markdown":{"get":{"operationId":"items.markdown","summary":"Get the content of a page as Markdown","description":"Returns the content readers see as GitHub-flavored Markdown.\n\nRequires the permission `item.view` on the item in `pageId`.","tags":["Pages"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The content.","content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"ID of the page."},"markdown":{"type":"string","description":"The content as GitHub-flavored Markdown."},"revision":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the stored state."},"updatedAt":{"type":"string","format":"date-time","description":"When the content was last stored. ISO 8601 timestamp in UTC."}},"required":["itemId","markdown","revision","updatedAt"],"additionalProperties":false,"description":"The content of a page as Markdown."},"example":{"itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","markdown":"Connect through WireGuard.\n","revision":4,"updatedAt":"2026-10-05T08:10:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/pages/{pageId}/mention-access":{"get":{"operationId":"comments.mentionAccess","summary":"Check whether mentioned people can read a page","description":"Tells the author of a comment or of the page while writing which mentioned people cannot read the page. They are not notified. People the caller cannot see are left out.\n\nRequires one of the permissions `item.comment`, `item.edit` on the item in `pageId`; the request decides which.","tags":["Comments"],"x-lunedo-permission":{"action":"item.comment","alternatives":["item.edit"],"resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page or blog post.","schema":{"type":"string","format":"uuid"}},{"name":"accountIds","in":"query","required":true,"description":"Up to 20 account IDs, separated by commas.","schema":{"type":"string","maxLength":800}}],"responses":{"200":{"description":"Access per person.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"The mentioned account."},"hasAccess":{"type":"boolean","description":"Whether the person can read the page and would be notified."}},"required":["accountId","hasAccess"],"additionalProperties":false,"description":"Access of a mentioned person."},"description":"Access of the mentioned people."},"example":[{"accountId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","hasAccess":false}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/pages/{pageId}/mode":{"put":{"operationId":"versions.changeMode","summary":"Change the editing mode","description":"Switches between publish and live mode. Switching to publish mode makes the current content the published version. Switching to live mode with unpublished changes needs `confirmDraft`, because readers see them at once.\n\nRequires the permission `item.publish` on the item in `pageId`.","tags":["Versions"],"x-lunedo-permission":{"action":"item.publish","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["publish","live"],"description":"Editing mode of a page: `publish` (readers see the last published version while editors work on a draft) or `live` (readers see every change at once). Folders and links are always `live`."},"confirmDraft":{"description":"Needed when switching to live mode while the draft has unpublished changes: they become visible to readers at once.","type":"boolean"}},"required":["mode"],"additionalProperties":false,"description":"The new editing mode."},"example":{"mode":"live","confirmDraft":true}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`draftPending`: The draft has unpublished changes. `knowledgeBaseMode`: Articles always use publish mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"draftPending":{"value":{"type":"urn:lunedo:problem:draftPending","title":"The draft has unpublished changes","status":409,"code":"draftPending"}},"knowledgeBaseMode":{"value":{"type":"urn:lunedo:problem:knowledgeBaseMode","title":"Articles always use publish mode","status":409,"code":"knowledgeBaseMode"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/pages/{pageId}/panels":{"get":{"operationId":"items.panels","summary":"Get the side information of a page","description":"Returns in one answer what the app shows around a page after its content: labels, reactions, the caller's watch state, the people editing it, versions, pages that link here, attachments and comments, each as its own endpoint returns it.\n\nRequires the permission `item.view` on the item in `pageId`.","tags":["Pages"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The side information.","content":{"application/json":{"schema":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string","description":"A label, lowercase, up to 100 characters."},"description":"Labels, sorted."},"reactions":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether reactions are turned on for the page's space."},"reactions":{"type":"array","items":{"type":"object","properties":{"emoji":{"type":"string","description":"The emoji."},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many people reacted with it."},"reacted":{"type":"boolean","description":"Whether the caller reacted with it."},"people":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"The first 20 people who reacted, in order."}},"required":["emoji","count","reacted","people"],"additionalProperties":false,"description":"One emoji with the people who reacted with it."},"description":"Reactions on the page."}},"required":["enabled","reactions"],"additionalProperties":false,"description":"Reactions on a page or blog post."},"watch":{"type":"object","properties":{"own":{"anyOf":[{"type":"object","properties":{"state":{"type":"string","enum":["watching","muted","notWatching"],"description":"`watching` delivers changes and comments, `muted` silences everything from it, `notWatching` stops watching it even when its space or meeting series is watched."},"keepActionable":{"type":"boolean","description":"Whether mentions, assigned tasks, shares with the person and access requests they can decide still arrive while muted."},"automatic":{"type":"boolean","description":"True when the caller watches because they created, edited or commented on it."}},"required":["state","keepActionable","automatic"],"additionalProperties":false},{"type":"null"}],"description":"The state the caller set for this item or space, or null."},"effective":{"anyOf":[{"type":"object","properties":{"state":{"type":"string","enum":["watching","muted","notWatching"],"description":"`watching` delivers changes and comments, `muted` silences everything from it, `notWatching` stops watching it even when its space or meeting series is watched."},"keepActionable":{"type":"boolean","description":"Whether mentions, assigned tasks, shares with the person and access requests they can decide still arrive while muted."},"source":{"type":"string","enum":["target","series","space"],"description":"Where the state comes from: the item or space itself, its meeting series or its space."}},"required":["state","keepActionable","source"],"additionalProperties":false},{"type":"null"}],"description":"The state that applies, or null when nothing is set."}},"required":["own","effective"],"additionalProperties":false,"description":"Whether the caller watches or muted the item or space."},"editors":{"type":"object","properties":{"editors":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when the caller may not see it.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null when there is none.","type":["string","null"]}},"required":["id","name","pictureRef"],"additionalProperties":false,"description":"A person editing the page."},"description":"People with the page open in the editor."}},"required":["editors"],"additionalProperties":false,"description":"Who is editing the page now."},"versions":{"type":"array","items":{"type":"object","properties":{"number":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the version, counting from 1."},"title":{"type":"string","description":"Title of the page in this version."},"note":{"type":"string","description":"Note of the person who published it, or empty."},"reason":{"type":"string","description":"Why the version exists: `published` (someone published), `session` (an editing session in live mode ended), `restored` (an older version was restored in live mode), `modeChanged` (the page switched modes), `imported` (a re-import applied the source version), `importedNotApplied` (a re-import added the source version to the history without applying it) or `copied` (the page was created as a copy of `copiedFrom`). New values can be added in later versions; handle unknown values.","x-extensible-enum":["published","session","restored","modeChanged","imported","importedNotApplied","copied"]},"restoredFrom":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The restored version, or null."},"copiedFrom":{"anyOf":[{"type":"object","properties":{"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The source, or null when the caller cannot read it or it was deleted permanently."},"title":{"description":"Title of the source when it was copied, or null when the caller cannot read the source.","type":["string","null"]},"path":{"description":"Path of the source in the web interface, or null when the caller cannot read the source.","type":["string","null"]}},"required":["itemId","title","path"],"additionalProperties":false},{"type":"null"}],"description":"Where a copy came from, for the first version of a copy; null otherwise."},"createdAt":{"type":"string","format":"date-time","description":"When the version was created. ISO 8601 timestamp in UTC."},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when the account no longer exists.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who published or restored, or null for versions of live sessions."},"contributors":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when the account no longer exists.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"Everyone who changed the content since the previous version."}},"required":["number","title","note","reason","restoredFrom","copiedFrom","createdAt","createdBy","contributors"],"additionalProperties":false,"description":"A version of a page."},"description":"Versions, newest first."},"backlinks":{"type":"array","items":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"Page that links here."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of that page in the addresses of the app."},"title":{"type":"string","description":"Title of that page."},"spaceId":{"type":"string","format":"uuid","description":"Space of that page."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."}},"required":["itemId","number","title","spaceId","spaceKey","spaceName"],"additionalProperties":false,"description":"A page that links to this page."},"description":"Pages that link here, ordered by title."},"attachments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the attachment."},"itemId":{"type":"string","format":"uuid","description":"Page or blog post the file is attached to."},"name":{"type":"string","description":"File name of the current version."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size of the current version in bytes."},"contentType":{"type":"string","description":"Media type, decided from the content of the file."},"preview":{"type":"string","description":"How the file can be previewed; `none` offers only the download. New values can be added in later versions; handle unknown values.","x-extensible-enum":["image","pdf","video","audio","text","code","markdown","csv","svg","word","excel","none"]},"inline":{"type":"boolean","description":"Whether browsers may show the file directly: images, video and audio."},"tooLargeForPreview":{"type":"boolean","description":"Whether the image has more than 100 megapixels. Such images get no smaller version; pages and previews show them as a file that opens in full size."},"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the current version."},"versions":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of stored versions."},"draft":{"anyOf":[{"type":"string","x-extensible-enum":["added","changed","deleted"]},{"type":"null"}],"description":"Only for people who can edit the page: `added` when readers do not see the file until the next publication, `changed` when readers still see an earlier version, `deleted` when the file was deleted in the draft and readers still see it until the next publication; restore it to keep it. Null when readers see this version. New values can be added in later versions; handle unknown values."},"uploadedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who uploaded the current version."},"uploadedAt":{"type":"string","format":"date-time","description":"When the current version was uploaded. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the file was first attached. ISO 8601 timestamp in UTC."}},"required":["id","itemId","name","size","contentType","preview","inline","tooLargeForPreview","version","versions","draft","uploadedBy","uploadedAt","createdAt"],"additionalProperties":false,"description":"A file attached to a page or blog post."},"description":"Attachments, ordered by name."},"comments":{"type":"object","properties":{"threads":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the comment."},"itemId":{"type":"string","format":"uuid","description":"Page or blog post the comment belongs to."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The comment this replies to, or null for a new thread."},"author":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null without one. Changes whenever the picture changes; load the picture from `GET /api/v1/accounts/{accountId}/picture`.","type":["string","null"]}},"required":["id","name","pictureRef"],"additionalProperties":false},{"type":"null"}],"description":"Author, or null for a deleted comment."},"body":{"anyOf":[{"description":"Comment content as ProseMirror JSON with the reduced comment schema: paragraphs with bold, italic, underline, strike, subscript, superscript, inline code and links, mentions, bullet and numbered lists and code blocks. No tables, images or headings.","$ref":"#/components/schemas/Schema113ae44d8375"},{"type":"null"}],"description":"Content, or null for a deleted comment."},"deleted":{"type":"boolean","description":"Whether the comment was deleted. A deleted comment with replies stays as a placeholder."},"createdAt":{"type":"string","format":"date-time","description":"When the comment was written. ISO 8601 timestamp in UTC."},"editedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the author last changed it, or null. ISO 8601 timestamp in UTC."},"reactions":{"type":"array","items":{"type":"object","properties":{"emoji":{"type":"string","description":"The emoji."},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many people reacted with it."},"reacted":{"type":"boolean","description":"Whether the caller reacted with it."},"people":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"The first 20 people who reacted, in order."}},"required":["emoji","count","reacted","people"],"additionalProperties":false,"description":"One emoji with the people who reacted with it."},"description":"Reactions, empty when reactions are turned off."},"quote":{"description":"For inline comments, the text the comment refers to; for comments on a whiteboard element, the text of the element (possibly empty). Readers see inline comments only once their text is published.","type":["string","null"]},"anchor":{"type":"string","description":"`page` for a comment on the whole page or whiteboard, `inline` for a comment on text in it, `element` for a comment on an element of a whiteboard, `detached` for a comment whose text or element no longer exists. Detached comments are listed with the page comments. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","inline","element","detached"]},"elementId":{"description":"The whiteboard element the comment refers to, also after it was removed, or null.","type":["string","null"]},"resolvedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the inline comment was resolved, or null while it is open. ISO 8601 timestamp in UTC."},"resolvedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null without one. Changes whenever the picture changes; load the picture from `GET /api/v1/accounts/{accountId}/picture`.","type":["string","null"]}},"required":["id","name","pictureRef"],"additionalProperties":false},{"type":"null"}],"description":"Who resolved it, or null."},"replies":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the comment."},"itemId":{"type":"string","format":"uuid","description":"Page or blog post the comment belongs to."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The comment this replies to, or null for a new thread."},"author":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null without one. Changes whenever the picture changes; load the picture from `GET /api/v1/accounts/{accountId}/picture`.","type":["string","null"]}},"required":["id","name","pictureRef"],"additionalProperties":false},{"type":"null"}],"description":"Author, or null for a deleted comment."},"body":{"anyOf":[{"description":"Comment content as ProseMirror JSON with the reduced comment schema: paragraphs with bold, italic, underline, strike, subscript, superscript, inline code and links, mentions, bullet and numbered lists and code blocks. No tables, images or headings.","$ref":"#/components/schemas/Schema113ae44d8375"},{"type":"null"}],"description":"Content, or null for a deleted comment."},"deleted":{"type":"boolean","description":"Whether the comment was deleted. A deleted comment with replies stays as a placeholder."},"createdAt":{"type":"string","format":"date-time","description":"When the comment was written. ISO 8601 timestamp in UTC."},"editedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the author last changed it, or null. ISO 8601 timestamp in UTC."},"reactions":{"type":"array","items":{"type":"object","properties":{"emoji":{"type":"string","description":"The emoji."},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many people reacted with it."},"reacted":{"type":"boolean","description":"Whether the caller reacted with it."},"people":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"The first 20 people who reacted, in order."}},"required":["emoji","count","reacted","people"],"additionalProperties":false,"description":"One emoji with the people who reacted with it."},"description":"Reactions, empty when reactions are turned off."}},"required":["id","itemId","parentId","author","body","deleted","createdAt","editedAt","reactions"],"additionalProperties":false,"description":"A reply."},"description":"Replies, oldest first. Replies are one level deep."}},"required":["id","itemId","parentId","author","body","deleted","createdAt","editedAt","reactions","quote","anchor","elementId","resolvedAt","resolvedBy","replies"],"additionalProperties":false,"description":"A comment with its replies."},"description":"Threads, oldest first."},"people":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","description":"Name of the person."},"description":"Names of people mentioned in the comments that the caller may see, by account ID."}},"required":["threads","people"],"additionalProperties":false,"description":"Comments of a page."}},"required":["labels","reactions","watch","editors","versions","backlinks","attachments","comments"],"additionalProperties":false,"description":"What the app shows around a page."},"example":{"labels":["runbook","vpn"],"reactions":{"enabled":true,"reactions":[]},"watch":{"own":null,"effective":{"state":"watching","keepActionable":true,"source":"space"}},"editors":{"editors":[]},"versions":[],"backlinks":[],"attachments":[],"comments":{"threads":[],"people":{}}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/pages/{pageId}/publish":{"post":{"operationId":"versions.publish","summary":"Publish the draft","description":"Creates a version from the draft as the server holds it now; readers see it at once. Publishing a draft without changes, also when two people publish at the same moment, creates no second version.\n\nRequires the permission `item.publish` on the item in `pageId`.","tags":["Versions"],"x-lunedo-permission":{"action":"item.publish","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"description":"Short note on what changed, up to 500 characters.","type":"string","maxLength":1000},"reviewed":{"description":"For knowledge base articles: the author checked the whole content, so the publication also counts as a review. Default false.","type":"boolean"}},"additionalProperties":false,"description":"Publication of the draft."},"example":{"note":"Added the section on lost devices"}}}},"responses":{"200":{"description":"The published version.","content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The version readers see now."},"created":{"type":"boolean","description":"Whether a new version was created. False when the draft had no changes, for example because someone else published it a moment before."}},"required":["version","created"],"additionalProperties":false,"description":"The result of publishing."},"example":{"version":8,"created":true}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidNote`: The note is too long.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidNote":{"value":{"type":"urn:lunedo:problem:invalidNote","title":"The note is too long","status":400,"code":"invalidNote"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notArticle`: The item is not an article of a knowledge base. `notPublishMode`: The page is not in publish mode. `requiredSectionsEmpty`: Required sections are empty.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notArticle":{"value":{"type":"urn:lunedo:problem:notArticle","title":"The item is not an article of a knowledge base","status":409,"code":"notArticle"}},"notPublishMode":{"value":{"type":"urn:lunedo:problem:notPublishMode","title":"The page is not in publish mode","status":409,"code":"notPublishMode"}},"requiredSectionsEmpty":{"value":{"type":"urn:lunedo:problem:requiredSectionsEmpty","title":"Required sections are empty","status":409,"code":"requiredSectionsEmpty"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/pages/{pageId}/reactions":{"get":{"operationId":"comments.reactions","summary":"List the reactions on a page","description":"Lists the reactions on a page or blog post with the people who reacted.\n\nRequires the permission `item.view` on the item in `pageId`.","tags":["Comments"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page or blog post.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The reactions.","content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether reactions are turned on for the page's space."},"reactions":{"type":"array","items":{"type":"object","properties":{"emoji":{"type":"string","description":"The emoji."},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many people reacted with it."},"reacted":{"type":"boolean","description":"Whether the caller reacted with it."},"people":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"The first 20 people who reacted, in order."}},"required":["emoji","count","reacted","people"],"additionalProperties":false,"description":"One emoji with the people who reacted with it."},"description":"Reactions on the page."}},"required":["enabled","reactions"],"additionalProperties":false,"description":"Reactions on a page or blog post."},"example":{"enabled":true,"reactions":[{"emoji":"👍","count":1,"reacted":true,"people":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Lukas Hofer"}]}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/pages/{pageId}/reactions/{emoji}":{"delete":{"operationId":"comments.unreact","summary":"Remove a reaction from a page","description":"Removes the caller's reaction with the emoji. Removing a reaction that does not exist changes nothing.\n\nRequires the permission `item.react` on the item in `pageId`.","tags":["Comments"],"x-lunedo-permission":{"action":"item.react","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page or blog post.","schema":{"type":"string","format":"uuid"}},{"name":"emoji","in":"path","required":true,"description":"The emoji, URL-encoded.","schema":{"type":"string","minLength":1,"maxLength":64}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"put":{"operationId":"comments.react","summary":"React to a page","description":"Adds the caller's reaction with an emoji to a page or blog post. Adding it again changes nothing.\n\nRequires the permission `item.react` on the item in `pageId`.","tags":["Comments"],"x-lunedo-permission":{"action":"item.react","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page or blog post.","schema":{"type":"string","format":"uuid"}},{"name":"emoji","in":"path","required":true,"description":"The emoji, URL-encoded.","schema":{"type":"string","minLength":1,"maxLength":64}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidEmoji`: The reaction is not a single emoji. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidEmoji":{"value":{"type":"urn:lunedo:problem:invalidEmoji","title":"The reaction is not a single emoji","status":400,"code":"invalidEmoji"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`reactionsDisabled`: Reactions are turned off. `tooManyReactions`: Too many reactions from one person.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"reactionsDisabled":{"value":{"type":"urn:lunedo:problem:reactionsDisabled","title":"Reactions are turned off","status":409,"code":"reactionsDisabled"}},"tooManyReactions":{"value":{"type":"urn:lunedo:problem:tooManyReactions","title":"Too many reactions from one person","status":409,"code":"tooManyReactions"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/pages/{pageId}/related-labels":{"get":{"operationId":"reports.relatedLabels","summary":"List labels related to a page","description":"Lists labels that are used on pages the caller can read together with the labels of the page, or with the given labels, most used first, as the related labels block shows them.\n\nRequires the permission `item.view` on the item in `pageId`.","tags":["Reports"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page that shows the block.","schema":{"type":"string","format":"uuid"}},{"name":"labels","in":"query","required":false,"description":"Labels to start from. Leave it out for the labels of the page. Up to 20 labels, separated by commas.","schema":{"type":"string","maxLength":2100}}],"responses":{"200":{"description":"The labels.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string","description":"A label."},"href":{"type":"string","description":"Path of the label in the space of the page."}},"required":["label","href"],"additionalProperties":false,"description":"A label used together with the given labels."},"description":"Labels, most used first."},"example":[{"label":"network","href":"/spaces/ITOPS/labels/network"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/pages/{pageId}/share-links":{"get":{"operationId":"shareLinks.list","summary":"List the share links of a page","description":"Lists the links that are not revoked, with what the organization allows for new ones.\n\nRequires the permission `item.share` on the item in `pageId`.","tags":["Share links"],"x-lunedo-permission":{"action":"item.share","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The links.","content":{"application/json":{"schema":{"type":"object","properties":{"links":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the link."},"token":{"description":"Secret part of the address: the instance URL followed by `/s/` and the token. Shown to people who may share the page.","type":["string","null"]},"itemId":{"type":"string","format":"uuid","description":"The page the link opens."},"scope":{"type":"string","description":"Who can open the link. New values can be added in later versions; handle unknown values.","x-extensible-enum":["people","organization","instance","anyone"]},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the link stops working. ISO 8601 timestamp in UTC."},"hasPassword":{"type":"boolean","description":"Whether the link asks for a password."},"people":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["account","group"],"description":"`account` for a person, `group` for a group."},"id":{"type":"string","format":"uuid","description":"ID of the account or group."},"name":{"description":"Name.","type":["string","null"]}},"required":["kind","id","name"],"additionalProperties":false,"description":"A person or group the link is for."},"description":"For the scope `people`: who can open the link."},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who created the link."},"createdAt":{"type":"string","format":"date-time","description":"When the link was created. ISO 8601 timestamp in UTC."},"visitors":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Signed-in people who opened the link."}},"required":["id","token","itemId","scope","expiresAt","hasPassword","people","createdBy","createdAt","visitors"],"additionalProperties":false,"description":"A share link of a page."},"description":"Active links, newest first."},"options":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether the organization allows share links."},"anyone":{"type":"boolean","description":"Whether links for anyone are allowed."},"anyoneMaxDays":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Longest lifetime of a link for anyone, in days."},"peopleOnly":{"type":"boolean","description":"True in a confidential space, where links can only name specific people."}},"required":["enabled","anyone","anyoneMaxDays","peopleOnly"],"additionalProperties":false,"description":"What the organization allows."}},"required":["links","options"],"additionalProperties":false,"description":"Share links of a page."},"example":{"links":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","token":"Yk3mR0vQx8LfJ2aB7cT9wE4nU6pH1sD5gK0zV3iM8oA2qX7r","itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","scope":"organization","expiresAt":"2026-11-30T00:00:00.000Z","hasPassword":false,"people":[],"createdBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a21","name":"Lukas Hofer"},"createdAt":"2026-10-01T09:30:00.000Z","visitors":3}],"options":{"enabled":true,"anyone":false,"anyoneMaxDays":30,"peopleOnly":false}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"shareLinks.create","summary":"Create a share link","description":"Creates a link that opens the page for reading: for specific people, signed-in members of the organization, signed-in users of the instance, or anyone. Links for anyone must be allowed by the organization and need an expiry within its maximum. The token is returned only once; the password is stored as a hash.\n\nRequires the permission `item.share` on the item in `pageId`.","tags":["Share links"],"x-lunedo-permission":{"action":"item.share","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"scope":{"type":"string","enum":["people","organization","instance","anyone"],"description":"Who can open the link."},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the link stops working. ISO 8601 timestamp; an offset is allowed."},"password":{"description":"Password the link asks for. Leave it out for none.","anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"people":{"description":"For the scope `people`: who can open the link.","maxItems":100,"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["account","group"],"description":"`account` for a person, `group` for a group."},"id":{"type":"string","format":"uuid","description":"ID of the account or group."}},"required":["kind","id"],"additionalProperties":false,"description":"A person or group."}}},"required":["scope"],"additionalProperties":false,"description":"A new share link."},"example":{"scope":"organization","expiresAt":"2026-11-30T00:00:00Z"}}}},"responses":{"201":{"description":"The link with its token.","content":{"application/json":{"schema":{"type":"object","properties":{"link":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the link."},"token":{"description":"Secret part of the address: the instance URL followed by `/s/` and the token. Shown to people who may share the page.","type":["string","null"]},"itemId":{"type":"string","format":"uuid","description":"The page the link opens."},"scope":{"type":"string","description":"Who can open the link. New values can be added in later versions; handle unknown values.","x-extensible-enum":["people","organization","instance","anyone"]},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the link stops working. ISO 8601 timestamp in UTC."},"hasPassword":{"type":"boolean","description":"Whether the link asks for a password."},"people":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["account","group"],"description":"`account` for a person, `group` for a group."},"id":{"type":"string","format":"uuid","description":"ID of the account or group."},"name":{"description":"Name.","type":["string","null"]}},"required":["kind","id","name"],"additionalProperties":false,"description":"A person or group the link is for."},"description":"For the scope `people`: who can open the link."},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who created the link."},"createdAt":{"type":"string","format":"date-time","description":"When the link was created. ISO 8601 timestamp in UTC."},"visitors":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Signed-in people who opened the link."}},"required":["id","token","itemId","scope","expiresAt","hasPassword","people","createdBy","createdAt","visitors"],"additionalProperties":false,"description":"A share link of a page."},"token":{"type":"string","description":"Secret part of the link address. The address is the instance URL followed by `/s/` and the token."}},"required":["link","token"],"additionalProperties":false,"description":"The new link."},"example":{"link":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","token":"Yk3mR0vQx8LfJ2aB7cT9wE4nU6pH1sD5gK0zV3iM8oA2qX7r","itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","scope":"organization","expiresAt":"2026-11-30T00:00:00.000Z","hasPassword":false,"people":[],"createdBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a21","name":"Lukas Hofer"},"createdAt":"2026-10-01T09:30:00.000Z","visitors":3},"token":"Yk3mR0vQx8LfJ2aB7cT9wE4nU6pH1sD5gK0zV3iM8oA2qX7r"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `expiryInPast`: The expiry lies in the past. `expiryRequired`: An expiry date is required. `expiryTooLate`: The expiry exceeds the maximum lifetime. `invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid. `invalidPassword`: The link password is not valid. `invalidScope`: The link scope cannot be used here. `peopleRequired`: The link needs at least one person or group. `tooManyPeople`: The link names too many people or groups.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"expiryInPast":{"value":{"type":"urn:lunedo:problem:expiryInPast","title":"The expiry lies in the past","status":400,"code":"expiryInPast"}},"expiryRequired":{"value":{"type":"urn:lunedo:problem:expiryRequired","title":"An expiry date is required","status":400,"code":"expiryRequired"}},"expiryTooLate":{"value":{"type":"urn:lunedo:problem:expiryTooLate","title":"The expiry exceeds the maximum lifetime","status":400,"code":"expiryTooLate"}},"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidPassword":{"value":{"type":"urn:lunedo:problem:invalidPassword","title":"The link password is not valid","status":400,"code":"invalidPassword"}},"invalidScope":{"value":{"type":"urn:lunedo:problem:invalidScope","title":"The link scope cannot be used here","status":400,"code":"invalidScope"}},"peopleRequired":{"value":{"type":"urn:lunedo:problem:peopleRequired","title":"The link needs at least one person or group","status":400,"code":"peopleRequired"}},"tooManyPeople":{"value":{"type":"urn:lunedo:problem:tooManyPeople","title":"The link names too many people or groups","status":400,"code":"tooManyPeople"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`confidentialGuestsBySpaceAdmins`: Only space administrators give guests access to a confidential space. `csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"confidentialGuestsBySpaceAdmins":{"value":{"type":"urn:lunedo:problem:confidentialGuestsBySpaceAdmins","title":"Only space administrators give guests access to a confidential space","status":403,"code":"confidentialGuestsBySpaceAdmins"}},"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`anyoneLinksDisabled`: Links for anyone are turned off. `restrictedPage`: A restricted page cannot be opened by anyone with a link. `shareLinksDisabled`: Share links are turned off.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"anyoneLinksDisabled":{"value":{"type":"urn:lunedo:problem:anyoneLinksDisabled","title":"Links for anyone are turned off","status":409,"code":"anyoneLinksDisabled"}},"restrictedPage":{"value":{"type":"urn:lunedo:problem:restrictedPage","title":"A restricted page cannot be opened by anyone with a link","status":409,"code":"restrictedPage"}},"shareLinksDisabled":{"value":{"type":"urn:lunedo:problem:shareLinksDisabled","title":"Share links are turned off","status":409,"code":"shareLinksDisabled"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/pages/{pageId}/share-links/{linkId}":{"delete":{"operationId":"shareLinks.revoke","summary":"Revoke a share link","description":"Revokes the link at once. Access that people had only through it ends.\n\nRequires the permission `item.share` on the item in `pageId`.","tags":["Share links"],"x-lunedo-permission":{"action":"item.share","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}},{"name":"linkId","in":"path","required":true,"description":"ID of the share link.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`linkNotFound`: The link does not exist, has expired or was revoked. `notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"linkNotFound":{"value":{"type":"urn:lunedo:problem:linkNotFound","title":"The link does not exist, has expired or was revoked","status":404,"code":"linkNotFound"}},"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"patch":{"operationId":"shareLinks.update","summary":"Change a share link","description":"Changes scope, expiry, password or people of a link. The address stays the same.\n\nRequires the permission `item.share` on the item in `pageId`.","tags":["Share links"],"x-lunedo-permission":{"action":"item.share","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}},{"name":"linkId","in":"path","required":true,"description":"ID of the share link.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"scope":{"type":"string","enum":["people","organization","instance","anyone"],"description":"Who can open the link."},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the link stops working. ISO 8601 timestamp; an offset is allowed."},"password":{"description":"Password the link asks for. Leave it out for none.","anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"people":{"description":"For the scope `people`: who can open the link.","maxItems":100,"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["account","group"],"description":"`account` for a person, `group` for a group."},"id":{"type":"string","format":"uuid","description":"ID of the account or group."}},"required":["kind","id"],"additionalProperties":false,"description":"A person or group."}}},"additionalProperties":false,"description":"Changes of a share link."},"example":{"expiresAt":"2026-12-31T00:00:00Z"}}}},"responses":{"200":{"description":"The link.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the link."},"token":{"description":"Secret part of the address: the instance URL followed by `/s/` and the token. Shown to people who may share the page.","type":["string","null"]},"itemId":{"type":"string","format":"uuid","description":"The page the link opens."},"scope":{"type":"string","description":"Who can open the link. New values can be added in later versions; handle unknown values.","x-extensible-enum":["people","organization","instance","anyone"]},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the link stops working. ISO 8601 timestamp in UTC."},"hasPassword":{"type":"boolean","description":"Whether the link asks for a password."},"people":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["account","group"],"description":"`account` for a person, `group` for a group."},"id":{"type":"string","format":"uuid","description":"ID of the account or group."},"name":{"description":"Name.","type":["string","null"]}},"required":["kind","id","name"],"additionalProperties":false,"description":"A person or group the link is for."},"description":"For the scope `people`: who can open the link."},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who created the link."},"createdAt":{"type":"string","format":"date-time","description":"When the link was created. ISO 8601 timestamp in UTC."},"visitors":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Signed-in people who opened the link."}},"required":["id","token","itemId","scope","expiresAt","hasPassword","people","createdBy","createdAt","visitors"],"additionalProperties":false,"description":"A share link of a page."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","token":"Yk3mR0vQx8LfJ2aB7cT9wE4nU6pH1sD5gK0zV3iM8oA2qX7r","itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","scope":"organization","expiresAt":"2026-11-30T00:00:00.000Z","hasPassword":false,"people":[],"createdBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a21","name":"Lukas Hofer"},"createdAt":"2026-10-01T09:30:00.000Z","visitors":3}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `expiryInPast`: The expiry lies in the past. `expiryRequired`: An expiry date is required. `expiryTooLate`: The expiry exceeds the maximum lifetime. `invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid. `invalidPassword`: The link password is not valid. `invalidScope`: The link scope cannot be used here. `peopleRequired`: The link needs at least one person or group. `tooManyPeople`: The link names too many people or groups.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"expiryInPast":{"value":{"type":"urn:lunedo:problem:expiryInPast","title":"The expiry lies in the past","status":400,"code":"expiryInPast"}},"expiryRequired":{"value":{"type":"urn:lunedo:problem:expiryRequired","title":"An expiry date is required","status":400,"code":"expiryRequired"}},"expiryTooLate":{"value":{"type":"urn:lunedo:problem:expiryTooLate","title":"The expiry exceeds the maximum lifetime","status":400,"code":"expiryTooLate"}},"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidPassword":{"value":{"type":"urn:lunedo:problem:invalidPassword","title":"The link password is not valid","status":400,"code":"invalidPassword"}},"invalidScope":{"value":{"type":"urn:lunedo:problem:invalidScope","title":"The link scope cannot be used here","status":400,"code":"invalidScope"}},"peopleRequired":{"value":{"type":"urn:lunedo:problem:peopleRequired","title":"The link needs at least one person or group","status":400,"code":"peopleRequired"}},"tooManyPeople":{"value":{"type":"urn:lunedo:problem:tooManyPeople","title":"The link names too many people or groups","status":400,"code":"tooManyPeople"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`confidentialGuestsBySpaceAdmins`: Only space administrators give guests access to a confidential space. `csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"confidentialGuestsBySpaceAdmins":{"value":{"type":"urn:lunedo:problem:confidentialGuestsBySpaceAdmins","title":"Only space administrators give guests access to a confidential space","status":403,"code":"confidentialGuestsBySpaceAdmins"}},"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`linkNotFound`: The link does not exist, has expired or was revoked. `notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"linkNotFound":{"value":{"type":"urn:lunedo:problem:linkNotFound","title":"The link does not exist, has expired or was revoked","status":404,"code":"linkNotFound"}},"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`anyoneLinksDisabled`: Links for anyone are turned off. `restrictedPage`: A restricted page cannot be opened by anyone with a link.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"anyoneLinksDisabled":{"value":{"type":"urn:lunedo:problem:anyoneLinksDisabled","title":"Links for anyone are turned off","status":409,"code":"anyoneLinksDisabled"}},"restrictedPage":{"value":{"type":"urn:lunedo:problem:restrictedPage","title":"A restricted page cannot be opened by anyone with a link","status":409,"code":"restrictedPage"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/pages/{pageId}/tasks":{"get":{"operationId":"tasks.statuses","summary":"Get the status of the tasks on a page","description":"Returns the status of every task on the page. The status is kept apart from the content, so the draft and the published version show the same status. Readers get the tasks of the published content, editors also those of the draft.\n\nRequires the permission `item.view` on the item in `pageId`.","tags":["Tasks"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page or blog post.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Status per task.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the task, as in the `id` attribute of the task item."},"done":{"type":"boolean","description":"Whether the task is done."},"changedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the status last changed, or null. ISO 8601 timestamp in UTC."},"changedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who changed it last, or null."}},"required":["id","done","changedAt","changedBy"],"additionalProperties":false,"description":"Status of a task."},"description":"Statuses in the order of the page."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5c01","done":true,"changedAt":"2026-10-07T09:00:00.000Z","changedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Lukas Hofer"}}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/pages/{pageId}/tasks/{taskId}/status":{"put":{"operationId":"tasks.setStatusOnPage","summary":"Set the status of a task on a page","description":"Sets a task of the page to done or open, for editors of the page. A task ID that does not exist yet is created for this page with the given status, so a task can be checked before its content is stored, for example right after pasting a done task. Every change records who made it and when.\n\nRequires the permission `item.edit` on the item in `pageId`.","tags":["Tasks"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page or blog post.","schema":{"type":"string","format":"uuid"}},{"name":"taskId","in":"path","required":true,"description":"ID of the task.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"done":{"type":"boolean","description":"True for done, false for open."}},"required":["done"],"additionalProperties":false,"description":"The new status. Setting the current status again changes nothing."},"example":{"done":true}}}},"responses":{"200":{"description":"The new status.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the task, as in the `id` attribute of the task item."},"done":{"type":"boolean","description":"Whether the task is done."},"changedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the status last changed, or null. ISO 8601 timestamp in UTC."},"changedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who changed it last, or null."}},"required":["id","done","changedAt","changedBy"],"additionalProperties":false,"description":"Status of a task."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5c01","done":true,"changedAt":"2026-10-07T09:00:00.000Z","changedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Lukas Hofer"}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/pages/{pageId}/versions":{"get":{"operationId":"versions.versions","summary":"List the versions of a page","description":"Lists all versions, newest first. Versions are kept without limit. The draft is not part of this list.\n\nRequires the permission `item.view` on the item in `pageId`.","tags":["Versions"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Versions.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"number":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the version, counting from 1."},"title":{"type":"string","description":"Title of the page in this version."},"note":{"type":"string","description":"Note of the person who published it, or empty."},"reason":{"type":"string","description":"Why the version exists: `published` (someone published), `session` (an editing session in live mode ended), `restored` (an older version was restored in live mode), `modeChanged` (the page switched modes), `imported` (a re-import applied the source version), `importedNotApplied` (a re-import added the source version to the history without applying it) or `copied` (the page was created as a copy of `copiedFrom`). New values can be added in later versions; handle unknown values.","x-extensible-enum":["published","session","restored","modeChanged","imported","importedNotApplied","copied"]},"restoredFrom":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The restored version, or null."},"copiedFrom":{"anyOf":[{"type":"object","properties":{"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The source, or null when the caller cannot read it or it was deleted permanently."},"title":{"description":"Title of the source when it was copied, or null when the caller cannot read the source.","type":["string","null"]},"path":{"description":"Path of the source in the web interface, or null when the caller cannot read the source.","type":["string","null"]}},"required":["itemId","title","path"],"additionalProperties":false},{"type":"null"}],"description":"Where a copy came from, for the first version of a copy; null otherwise."},"createdAt":{"type":"string","format":"date-time","description":"When the version was created. ISO 8601 timestamp in UTC."},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when the account no longer exists.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who published or restored, or null for versions of live sessions."},"contributors":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when the account no longer exists.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"Everyone who changed the content since the previous version."}},"required":["number","title","note","reason","restoredFrom","copiedFrom","createdAt","createdBy","contributors"],"additionalProperties":false,"description":"A version of a page."},"description":"Versions, newest first."},"example":[{"number":7,"title":"VPN access for remote staff","note":"Added the section on lost devices","reason":"published","restoredFrom":null,"copiedFrom":null,"createdAt":"2026-10-03T14:20:00.000Z","createdBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"contributors":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"}]}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/pages/{pageId}/versions/{number}":{"get":{"operationId":"versions.version","summary":"Get a version","description":"Returns a version with its title and content.\n\nRequires the permission `item.view` on the item in `pageId`.","tags":["Versions"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}},{"name":"number","in":"path","required":true,"description":"Number of the version.","schema":{"type":"integer","minimum":1,"maximum":2147483647}}],"responses":{"200":{"description":"The version.","content":{"application/json":{"schema":{"type":"object","properties":{"number":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the version, counting from 1."},"title":{"type":"string","description":"Title of the page in this version."},"note":{"type":"string","description":"Note of the person who published it, or empty."},"reason":{"type":"string","description":"Why the version exists: `published` (someone published), `session` (an editing session in live mode ended), `restored` (an older version was restored in live mode), `modeChanged` (the page switched modes), `imported` (a re-import applied the source version), `importedNotApplied` (a re-import added the source version to the history without applying it) or `copied` (the page was created as a copy of `copiedFrom`). New values can be added in later versions; handle unknown values.","x-extensible-enum":["published","session","restored","modeChanged","imported","importedNotApplied","copied"]},"restoredFrom":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The restored version, or null."},"copiedFrom":{"anyOf":[{"type":"object","properties":{"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The source, or null when the caller cannot read it or it was deleted permanently."},"title":{"description":"Title of the source when it was copied, or null when the caller cannot read the source.","type":["string","null"]},"path":{"description":"Path of the source in the web interface, or null when the caller cannot read the source.","type":["string","null"]}},"required":["itemId","title","path"],"additionalProperties":false},{"type":"null"}],"description":"Where a copy came from, for the first version of a copy; null otherwise."},"createdAt":{"type":"string","format":"date-time","description":"When the version was created. ISO 8601 timestamp in UTC."},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when the account no longer exists.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who published or restored, or null for versions of live sessions."},"contributors":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when the account no longer exists.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"Everyone who changed the content since the previous version."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"references":{"type":"object","properties":{"people":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","description":"Name of the person."},"description":"Names of mentioned people the caller may see, by account ID."},"pictures":{"description":"Profile pictures of the people in `people` that have one, by account ID. The picture is at `/api/v1/accounts/{accountId}/picture`.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","description":"Version of the profile picture."}},"pages":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"title":{"type":"string","description":"Title, or empty without access."},"spaceKey":{"type":"string","description":"Key of the page's space, or empty without access."},"kind":{"type":"string","description":"Kind of the item."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the item in the addresses of the app, or null without access."},"accessible":{"type":"boolean","description":"Whether the caller can open the page."},"inTrash":{"type":"boolean","description":"Whether the page is in the trash. Then only the title is given, as `In trash`."}},"required":["title","spaceKey","kind","number","accessible","inTrash"],"additionalProperties":false,"description":"A linked page."},"description":"Linked pages by ID."},"topics":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"title":{"type":"string","description":"Title of the running topic."},"status":{"type":"string","description":"Whether the topic is still open. New values can be added in later versions; handle unknown values.","x-extensible-enum":["open","closed"]}},"required":["title","status"],"additionalProperties":false,"description":"A running topic."},"description":"Running topics that topic updates and decisions in the document refer to, by ID, as far as the caller may see them."},"tooLargeImages":{"type":"array","items":{"type":"string","format":"uuid","description":"ID of an attachment."},"description":"Images in the document with more than 100 megapixels, as far as the caller may see them. They have no smaller version and are shown as a file that opens in full size."}},"required":["people","pages","topics","tooLargeImages"],"additionalProperties":false,"description":"What mentions and page links in the document point to, as far as the caller may see it."}},"required":["number","title","note","reason","restoredFrom","copiedFrom","createdAt","createdBy","contributors","document","references"],"additionalProperties":false,"description":"A version with its content."},"example":{"number":7,"title":"VPN access for remote staff","note":"Added the section on lost devices","reason":"published","restoredFrom":null,"copiedFrom":null,"createdAt":"2026-10-03T14:20:00.000Z","createdBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"contributors":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"}],"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"references":{"people":{},"pages":{},"topics":{},"tooLargeImages":[]}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/pages/{pageId}/versions/{number}/restore":{"post":{"operationId":"versions.restore","summary":"Restore a version","description":"In publish mode the version becomes the draft, to be reviewed and published; a draft with changes is kept as a discarded draft. In live mode it becomes the current content at once and creates a new version. History is never rewritten.\n\nRequires the permission `item.publish` on the item in `pageId`.","tags":["Versions"],"x-lunedo-permission":{"action":"item.publish","resource":"item","parameter":"pageId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"pageId","in":"path","required":true,"description":"ID of the page.","schema":{"type":"string","format":"uuid"}},{"name":"number","in":"path","required":true,"description":"Number of the version.","schema":{"type":"integer","minimum":1,"maximum":2147483647}}],"responses":{"200":{"description":"What happened.","content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["publish","live"],"description":"Editing mode of a page: `publish` (readers see the last published version while editors work on a draft) or `live` (readers see every change at once). Folders and links are always `live`."},"version":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The new version in live mode, or null in publish mode."}},"required":["mode","version"],"additionalProperties":false,"description":"The result of restoring."},"example":{"mode":"publish","version":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `versionNotFound`: The version does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"versionNotFound":{"value":{"type":"urn:lunedo:problem:versionNotFound","title":"The version does not exist","status":404,"code":"versionNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/pages/by-number/{number}/access-requests":{"post":{"operationId":"accessRequests.requestPageByNumber","summary":"Ask for access to a page by its number","description":"Like `POST /pages/{pageId}/access-requests`, for a page found by the number in its address in the app. The answer is the same whether or not the page exists.\n\nRequires the permission `instance.content.view` on the instance. Needs a signed-in session; API tokens are refused.","tags":["Access requests"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"sessionCookie":[]}],"parameters":[{"name":"number","in":"path","required":true,"description":"Number of the page, as shown in the addresses of the app.","schema":{"type":"string","pattern":"^[1-9][0-9]{0,14}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"default":"","description":"Why the access is needed, up to 1000 characters.","type":"string","maxLength":1000}},"additionalProperties":false,"description":"A request for access."},"example":{"message":"I need the runbook for the migration."}}}},"responses":{"202":{"description":"Accepted."},"400":{"description":"`invalidInput`: The request is not valid. `messageTooLong`: The message is too long.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"messageTooLong":{"value":{"type":"urn:lunedo:problem:messageTooLong","title":"The message is too long","status":400,"code":"messageTooLong"}}}}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`tooManyRequests`: Too many access requests today.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"tooManyRequests":{"value":{"type":"urn:lunedo:problem:tooManyRequests","title":"Too many access requests today","status":429,"code":"tooManyRequests"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/pages/by-number/{number}/view":{"get":{"operationId":"items.view","summary":"Get a page to read","description":"Returns in one answer what the app needs to show a page found by the number in its address: the item as `GET /items/by-number/{number}` returns it, the content readers see as `GET /pages/{pageId}/content` returns it, the statuses of its tasks and the caller's own access. `content` and `tasks` are null for an item that is not a page, and `content` also when the page has nothing readers may see yet. A number that does not exist and a number of an item the caller cannot see give the same `notFound` answer.\n\nRequires the permission `item.view` on the item in `number`.","tags":["Pages"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"number"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"number","in":"path","required":true,"description":"Number of the item, as shown in the addresses of the app.","schema":{"type":"string","pattern":"^[1-9][0-9]{0,14}$"}}],"responses":{"200":{"description":"The page.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the item."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app, unique in the instance. It never changes and is never reused."},"spaceId":{"type":"string","format":"uuid","description":"Space of the item."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Parent item, or null at the root of the tree."},"kind":{"type":"string","description":"`page`, `folder`, `link`, `blogPost`, `meetingSeries`, `meetingTopic` or `whiteboard`. Blog posts and topics are not part of the tree; they appear in the blog and the meetings of their space. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title. Empty for a link to content the caller cannot read."},"description":{"type":"string","description":"Short description of a folder."},"width":{"type":"string","enum":["fixed","full"],"description":"Page width: `fixed` or `full`."},"numberHeadings":{"type":"boolean","description":"Whether the headings of the page are numbered in the page, in print and in Word."},"mode":{"type":"string","enum":["publish","live"],"description":"Editing mode of a page: `publish` (readers see the last published version while editors work on a draft) or `live` (readers see every change at once). Folders and links are always `live`."},"published":{"type":"boolean","description":"Whether readers can see the page. False for a page in publish mode that was never published; only editors see it."},"archived":{"type":"boolean","description":"Whether the item is archived. Archived items are read-only."},"position":{"type":"string","description":"Sort key among the siblings. Items sort by it in binary order."},"hasChildren":{"type":"boolean","description":"Whether the item has children."},"viewRestriction":{"type":"string","enum":["none","own","inherited"],"description":"Whether only an access list may view the item: set on the item itself, on a page above, or not at all."},"editRestricted":{"type":"boolean","description":"Whether only an access list may edit the item."},"link":{"anyOf":[{"type":"object","properties":{"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Linked page, folder or whiteboard, or null for an address or when the caller cannot read it."},"url":{"description":"Linked `http` or `https` address, or null.","type":["string","null"]},"accessible":{"type":"boolean","description":"Whether the caller can open the target. If not, the title is empty."},"inTrash":{"type":"boolean","description":"Whether the target is in the trash. Only true for callers who could read it before."},"target":{"anyOf":[{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"Space of the target."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the target in the addresses of the app."},"spaceKey":{"type":"string","description":"Key of that space."},"kind":{"type":"string","description":"Kind of the target. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title of the target."}},"required":["spaceId","number","spaceKey","kind","title"],"additionalProperties":false},{"type":"null"}],"description":"The linked page, folder or whiteboard, or null."}},"required":["itemId","url","accessible","inTrash","target"],"additionalProperties":false,"description":"Where a link in the page tree points."},{"type":"null"}],"description":"Target of a link, or null for pages and folders."},"creatorId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Account that created the item, or null."},"contentLanguage":{"anyOf":[{"type":"string","description":"Content language as an ISO 639-1 code, or `other` for a language without its own word matching. Words are then matched as written. New values can be added in later versions; handle unknown values.","x-extensible-enum":["ar","ca","da","de","el","en","es","eu","fi","fr","ga","hi","hu","hy","id","it","lt","nb","ne","nl","pt","ro","ru","sr","sv","ta","tr","yi","other"]},{"type":"null"}],"description":"Language of the page content for search, or null to use the language of the space."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Type of an article in a knowledge base, or null for other items and articles without a type."},"translationOf":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Original article of a translation in a knowledge base, or null. A translation is listed below its original; `contentLanguage` is its language."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of the item, or null. The owner stays set when the person leaves; `owner.active` in the item details says whether the item has an active owner."},"status":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the status value."},"builtIn":{"anyOf":[{"type":"string","x-extensible-enum":["roughDraft","inProgress","readyForReview","verified"]},{"type":"null"}],"description":"Which default value this is, or null for a value a space admin added. Clients show the translated name of a default value unless `name` is set. New values can be added in later versions; handle unknown values."},"name":{"description":"Name set by a space admin, or null to show the default name.","type":["string","null"]},"color":{"type":"string","enum":["neutral","accent","info","success","warning","danger"],"description":"Color of the status: `neutral`, `accent`, `info`, `success`, `warning` or `danger`."}},"required":["id","builtIn","name","color"],"additionalProperties":false,"description":"A page status."},{"type":"null"}],"description":"Status of a page, or null when it has none or page status is turned off in the space."},"createdAt":{"type":"string","format":"date-time","description":"When the item was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the item last changed in the tree. ISO 8601 timestamp in UTC."},"contentUpdatedAt":{"type":"string","format":"date-time","description":"When the content of the page last changed. ISO 8601 timestamp in UTC."},"spaceKey":{"type":"string","description":"Key of the space. Empty when the caller sees the item only through a share or link."},"spaceName":{"type":"string","description":"Name of the space. Empty when the caller sees the item only through a share or link."},"spaceAccess":{"type":"boolean","description":"Whether the caller has access to the space; false when the item is visible only through a share or link."},"spaceContentLanguage":{"type":"string","description":"Content language of the space, which pages without a content language of their own use for search.","x-extensible-enum":["ar","ca","da","de","el","en","es","eu","fi","fr","ga","hi","hu","hy","id","it","lt","nb","ne","nl","pt","ro","ru","sr","sv","ta","tr","yi","other"]},"ancestors":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the ancestor."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the ancestor in the addresses of the app."},"kind":{"type":"string","description":"Kind of the ancestor. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title of the ancestor."},"published":{"type":"boolean","description":"Whether the ancestor counts as published: a folder, a link, a page in live mode or a page with a published version. Readers see a page only when every ancestor is published."}},"required":["id","number","kind","title","published"],"additionalProperties":false,"description":"An ancestor."},"description":"Ancestors from the root down to the parent."},"owner":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the owner."},"name":{"description":"Name of the owner, or null when the caller may not see the person.","type":["string","null"]},"jobTitle":{"description":"Job title the person entered on their profile, or null.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null without one. Changes whenever the picture changes; load the picture from `GET /api/v1/accounts/{accountId}/picture`.","type":["string","null"]},"email":{"description":"E-mail address of the owner, or null when the caller may not see it.","type":["string","null"]},"active":{"type":"boolean","description":"Whether the owner can still act: false when the account is deactivated or its membership in the organization ended."}},"required":["id","name","jobTitle","pictureRef","email","active"],"additionalProperties":false},{"type":"null"}],"description":"Owner of the item, or null when it has none."},"ownershipTransferable":{"type":"boolean","description":"Whether the caller may give the item a new owner."}},"required":["id","number","spaceId","parentId","kind","title","description","width","numberHeadings","mode","published","archived","position","hasChildren","viewRestriction","editRestricted","link","creatorId","contentLanguage","articleType","translationOf","ownerId","status","createdAt","updatedAt","contentUpdatedAt","spaceKey","spaceName","spaceAccess","spaceContentLanguage","ancestors","owner","ownershipTransferable"],"additionalProperties":false,"description":"An item with its place in the tree."},"content":{"anyOf":[{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"ID of the page."},"title":{"type":"string","description":"Title of the page as readers see it."},"version":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the version readers see, or null when the page has no version yet."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"schemaVersion":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Version of the editor schema the document follows."},"revision":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the stored state; it rises with every save."},"updatedAt":{"type":"string","format":"date-time","description":"When the content was last stored. ISO 8601 timestamp in UTC."},"updatedBy":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Account that stored the content last, or null."},"references":{"type":"object","properties":{"people":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","description":"Name of the person."},"description":"Names of mentioned people the caller may see, by account ID."},"pictures":{"description":"Profile pictures of the people in `people` that have one, by account ID. The picture is at `/api/v1/accounts/{accountId}/picture`.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","description":"Version of the profile picture."}},"pages":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"title":{"type":"string","description":"Title, or empty without access."},"spaceKey":{"type":"string","description":"Key of the page's space, or empty without access."},"kind":{"type":"string","description":"Kind of the item."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the item in the addresses of the app, or null without access."},"accessible":{"type":"boolean","description":"Whether the caller can open the page."},"inTrash":{"type":"boolean","description":"Whether the page is in the trash. Then only the title is given, as `In trash`."}},"required":["title","spaceKey","kind","number","accessible","inTrash"],"additionalProperties":false,"description":"A linked page."},"description":"Linked pages by ID."},"topics":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"title":{"type":"string","description":"Title of the running topic."},"status":{"type":"string","description":"Whether the topic is still open. New values can be added in later versions; handle unknown values.","x-extensible-enum":["open","closed"]}},"required":["title","status"],"additionalProperties":false,"description":"A running topic."},"description":"Running topics that topic updates and decisions in the document refer to, by ID, as far as the caller may see them."},"tooLargeImages":{"type":"array","items":{"type":"string","format":"uuid","description":"ID of an attachment."},"description":"Images in the document with more than 100 megapixels, as far as the caller may see them. They have no smaller version and are shown as a file that opens in full size."}},"required":["people","pages","topics","tooLargeImages"],"additionalProperties":false,"description":"What mentions and page links in the document point to, as far as the caller may see it."}},"required":["itemId","title","version","document","schemaVersion","revision","updatedAt","updatedBy","references"],"additionalProperties":false,"description":"The stored content of a page."},{"type":"null"}],"description":"The content readers see, or null for an item that is not a page or has no readable content."},"tasks":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the task, as in the `id` attribute of the task item."},"done":{"type":"boolean","description":"Whether the task is done."},"changedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the status last changed, or null. ISO 8601 timestamp in UTC."},"changedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who changed it last, or null."}},"required":["id","done","changedAt","changedBy"],"additionalProperties":false,"description":"Status of a task."}},{"type":"null"}],"description":"Statuses of the tasks in the order of the page, or null for an item that is not a page."},"access":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"The person."},"name":{"description":"Name, or null when hidden.","type":["string","null"]},"role":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"]},{"type":"null"}],"description":"What the person may do, or null for no access."},"reasons":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"Kind of reason. New values can be added in later versions; handle unknown values.","x-extensible-enum":["spaceRole","share","link"]},"role":{"description":"Role that the reason grants.","type":"string","enum":["reader","commenter","editor","admin"]},"via":{"type":"object","properties":{"type":{"type":"string","description":"How the role is held. New values can be added in later versions; handle unknown values.","x-extensible-enum":["account","group","organizationMembers","instanceUsers","visibility"]},"groupId":{"type":"string","format":"uuid","description":"The group."},"name":{"description":"Name of the group.","type":"string"},"visibility":{"description":"Visibility of the space that grants the role.","type":"string"}},"required":["type"],"additionalProperties":false,"description":"How a role in the space is held."},"itemId":{"type":"string","format":"uuid","description":"Page that was shared."},"itemTitle":{"description":"Its title, or null when the caller cannot see it.","type":["string","null"]},"inherited":{"description":"Whether the share comes from a page above.","type":"boolean"},"linkId":{"type":"string","format":"uuid","description":"The share link."},"scope":{"description":"Scope of the share link.","type":"string"},"inactive":{"type":"string","description":"Set when the entry is stored but grants nothing: `membershipEnded` means the person is no longer a member of the organization the space belongs to. It applies again if they become a member again. New values can be added in later versions; handle unknown values.","x-extensible-enum":["membershipEnded"]}},"required":["type"],"additionalProperties":false,"description":"Why a person has access, or an entry that has no effect."},"description":"Why: roles, shares and links."},"denial":{"description":"Why access is missing or narrower: `restricted`, `editRestricted`, `unpublished`, `inTrash`, `accountInactive` or `noAccess`.","type":["string","null"]},"restrictions":{"type":"array","items":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"Restricted page."},"title":{"description":"Its title, or null when hidden.","type":["string","null"]},"listed":{"type":"boolean","description":"Whether the person is on its access list."}},"required":["itemId","title","listed"],"additionalProperties":false,"description":"A view restriction that applies."},"description":"View restrictions on the page and above."},"editRestricted":{"anyOf":[{"type":"object","properties":{"listed":{"type":"boolean","description":"Whether the person may edit by the access list."}},"required":["listed"],"additionalProperties":false},{"type":"null"}],"description":"The edit restriction of the page, if any."},"published":{"type":"boolean","description":"Whether readers can see the page yet."}},"required":["accountId","name","role","reasons","denial","restrictions","editRestricted","published"],"additionalProperties":false,"description":"Why a person has or lacks access."}},"required":["item","content","tasks","access"],"additionalProperties":false,"description":"What the app needs to show a page."},"example":{"item":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","parentId":null,"kind":"page","title":"VPN access for remote staff","description":"","width":"fixed","numberHeadings":false,"mode":"publish","published":true,"archived":false,"position":"a1","hasChildren":false,"viewRestriction":"none","editRestricted":false,"link":null,"creatorId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","ownerId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","contentLanguage":null,"articleType":null,"translationOf":null,"status":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","builtIn":"verified","name":null,"color":"success"},"createdAt":"2026-10-05T08:00:00.000Z","updatedAt":"2026-10-05T08:00:00.000Z","contentUpdatedAt":"2026-10-05T08:00:00.000Z","spaceKey":"ITOPS","spaceName":"IT Operations","spaceAccess":true,"spaceContentLanguage":"en","ancestors":[],"owner":null,"ownershipTransferable":false},"content":{"itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","title":"VPN access for remote staff","version":7,"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"schemaVersion":4,"revision":4,"updatedAt":"2026-10-05T08:10:00.000Z","updatedBy":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","references":{"people":{},"pages":{},"topics":{},"tooLargeImages":[]}},"tasks":[],"access":{"accountId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a22","name":"Lukas Hofer","role":"reader","reasons":[{"type":"spaceRole","role":"reader","via":{"type":"group","groupId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a30","name":"IT Operations"}}],"denial":null,"restrictions":[],"editRestricted":null,"published":true}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/recent":{"get":{"operationId":"home.recent","summary":"List recently viewed items","description":"Lists what the caller viewed in the last 90 days. Only the caller sees it; there are no read receipts.\n\nRequires the permission `instance.content.view` on the instance.","tags":["Home"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"200":{"description":"Recently viewed items.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the page or blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app."},"kind":{"type":"string","description":"Kind of the item. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title readers see."},"spaceId":{"type":"string","format":"uuid","description":"Space of the item."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."},"mySpace":{"type":"boolean","description":"Whether the item lies in the caller's own personal space."},"viewedAt":{"type":"string","format":"date-time","description":"When the caller last viewed it. ISO 8601 timestamp in UTC."}},"required":["id","number","kind","title","spaceId","spaceKey","spaceName","mySpace","viewedAt"],"additionalProperties":false,"description":"A recently viewed item."},"description":"Items the caller viewed in the last 90 days, newest first. Only the caller sees this list."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"kind":"page","title":"VPN access for remote staff","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","mySpace":false,"viewedAt":"2026-10-07T08:00:00.000Z"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `personalOnly`: Only people have this personal data.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"personalOnly":{"value":{"type":"urn:lunedo:problem:personalOnly","title":"Only people have this personal data","status":400,"code":"personalOnly"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/reports/content-by-label":{"get":{"operationId":"reports.contentByLabel","summary":"List pages and blog posts with labels","description":"Lists pages and blog posts the caller can read that have the given labels, as the content by label block shows them. Archived content is left out unless the list is limited to archived spaces.\n\nRequires the permission `instance.content.view` on the instance.","tags":["Reports"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"labels","in":"query","required":false,"description":"Pages with these labels. Without labels the list is empty. Up to 20 labels, separated by commas.","schema":{"type":"string","maxLength":2100}},{"name":"matchAll","in":"query","required":false,"description":"`true` lists only pages with all of the labels, `false` (default) pages with any of them.","schema":{"default":"false","type":"string","enum":["true","false"]}},{"name":"spaceIds","in":"query","required":false,"description":"Only pages in these spaces. Leave it out for every space the caller can read. Up to 20 space IDs, separated by commas.","schema":{"type":"string","maxLength":800}},{"name":"kinds","in":"query","required":false,"description":"`page`, `blogPost` or both, separated by commas (default).","schema":{"type":"string","maxLength":40}},{"name":"sort","in":"query","required":false,"description":"`modified` (default) or `created`, newest first, or `title` from A to Z.","schema":{"default":"modified","type":"string","enum":["modified","created","title"]}},{"name":"reverse","in":"query","required":false,"description":"`true` reverses the order.","schema":{"default":"false","type":"string","enum":["true","false"]}},{"name":"limit","in":"query","required":false,"description":"Maximum number of pages, 1 to 100.","schema":{"default":5,"type":"integer","minimum":1,"maximum":100}},{"name":"excerpts","in":"query","required":false,"description":"`true` adds the excerpt of each page.","schema":{"default":"false","type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"The pages and blog posts.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the page or blog post."},"title":{"type":"string","description":"Title."},"kind":{"type":"string","description":"`page` or `blogPost`. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","blogPost"]},"path":{"type":"string","description":"Path in the web interface."},"space":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"name":{"type":"string","description":"Name of the space, or empty when the caller has no access to the space itself."}},"required":["id","name"],"additionalProperties":false,"description":"The space."},"labels":{"type":"array","items":{"type":"string","description":"A label."},"description":"Labels, sorted."},"excerpt":{"description":"Plain text of the excerpt when asked for, or the excerpt of a blog post; null otherwise.","type":["string","null"]},"parents":{"type":"array","items":{"type":"string","description":"Title of a parent."},"description":"Titles of the parents the caller can read, from the top down."},"contentUpdatedAt":{"type":"string","format":"date-time","description":"When its content last changed. ISO 8601 timestamp in UTC."}},"required":["id","title","kind","path","space","labels","excerpt","parents","contentUpdatedAt"],"additionalProperties":false,"description":"A page or blog post with a label."},"description":"Pages and blog posts in the requested order."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5c11","title":"VPN access for remote staff","kind":"page","path":"/spaces/ITOPS/pages/1042/vpn-access-for-remote-staff","space":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","name":"IT operations"},"labels":["how-to","vpn"],"excerpt":"Remote staff connect through WireGuard.","parents":["Network"],"contentUpdatedAt":"2026-10-05T08:10:00.000Z"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/reports/decisions":{"get":{"operationId":"reports.decisions","summary":"List decisions for a decision report","description":"Lists the decisions on published pages the caller can read, filtered by space, labels of the page and parent page, as the decision report block shows them. Empty decisions are left out.\n\nRequires the permission `instance.content.view` on the instance.","tags":["Reports"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"query","required":false,"description":"Only decisions in this space. Leave it out for every space the caller can read.","schema":{"type":"string","format":"uuid"}},{"name":"labels","in":"query","required":false,"description":"Only decisions on pages with at least one of these labels. Up to 20 labels, separated by commas.","schema":{"type":"string","maxLength":2100}},{"name":"parentId","in":"query","required":false,"description":"Only decisions on direct children of this page.","schema":{"type":"string","format":"uuid"}},{"name":"order","in":"query","required":false,"description":"`newest` (default) or `oldest` first, by the date of the page.","schema":{"default":"newest","type":"string","enum":["newest","oldest"]}},{"name":"cursor","in":"query","required":false,"description":"Cursor from `nextCursor` of the previous page.","schema":{"type":"string","maxLength":200}},{"name":"limit","in":"query","required":false,"description":"Maximum number of decisions, 1 to 100.","schema":{"default":50,"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"A page of decisions.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the decision."},"text":{"type":"string","description":"The decision as plain text."},"page":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the page."},"title":{"type":"string","description":"Title of the page."},"path":{"type":"string","description":"Path of the page in the web interface."}},"required":["id","title","path"],"additionalProperties":false,"description":"The page the decision was made on."},"date":{"type":"string","format":"date-time","description":"When that page was created. ISO 8601 timestamp in UTC."}},"required":["id","text","page","date"],"additionalProperties":false,"description":"A decision in a decision report."},"description":"Decisions in the requested order."},"nextCursor":{"description":"Cursor for the next page, or null on the last page.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"Decisions."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5d31","text":"Remote staff use WireGuard from November.","page":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5c11","title":"VPN access for remote staff","path":"/spaces/ITOPS/pages/1042/vpn-access-for-remote-staff"},"date":"2026-09-01T08:00:00.000Z"}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/reports/pages":{"get":{"operationId":"reports.pages","summary":"List pages for a page report","description":"Lists pages the caller can read, filtered by space and labels, as the page report block shows them. Archived pages are left out unless the report is limited to an archived space. Pages the caller cannot read are never counted or named.\n\nRequires the permission `instance.content.view` on the instance.","tags":["Reports"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"query","required":false,"description":"Only pages in this space. Leave it out for every space the caller can read.","schema":{"type":"string","format":"uuid"}},{"name":"labels","in":"query","required":false,"description":"Only pages with at least one of these labels. Up to 20 labels, separated by commas.","schema":{"type":"string","maxLength":2100}},{"name":"sort","in":"query","required":false,"description":"`modified` (default) or `created`, newest first, or `title` from A to Z.","schema":{"default":"modified","type":"string","enum":["modified","created","title"]}},{"name":"reverse","in":"query","required":false,"description":"`true` reverses the order.","schema":{"default":"false","type":"string","enum":["true","false"]}},{"name":"limit","in":"query","required":false,"description":"Maximum number of pages, 1 to 100.","schema":{"default":20,"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"The pages.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the page."},"title":{"type":"string","description":"Title of the page."},"path":{"type":"string","description":"Path of the page in the web interface."},"spaceId":{"type":"string","format":"uuid","description":"Space of the page."},"author":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"type":"string","description":"Name as the caller may see it."}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who created the page, or null when the caller may not see that person."},"createdAt":{"type":"string","format":"date-time","description":"When the page was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the content last changed. ISO 8601 timestamp in UTC."}},"required":["id","title","path","spaceId","author","createdAt","updatedAt"],"additionalProperties":false,"description":"A page in a page report."},"description":"Pages in the requested order."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5c11","title":"VPN access for remote staff","path":"/spaces/ITOPS/pages/1042/vpn-access-for-remote-staff","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","author":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-10-06T07:00:00.000Z"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/reports/properties":{"get":{"operationId":"reports.properties","summary":"List pages for a page properties report","description":"Lists pages the caller can read that have page properties, filtered by spaces, labels and the ID of the property set, with the values of the chosen properties, as the page properties report block shows them. Only the published version of a page counts; drafts are left out. Pages the caller cannot read are never counted, named or used for sorting.\n\nRequires the permission `instance.content.view` on the instance.","tags":["Reports"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceIds","in":"query","required":false,"description":"Only pages in these spaces. Leave it out for every space the caller can read. Up to 20 space IDs, separated by commas.","schema":{"type":"string","maxLength":800}},{"name":"labels","in":"query","required":false,"description":"Only pages with at least one of these labels. Up to 20 labels, separated by commas.","schema":{"type":"string","maxLength":2100}},{"name":"setId","in":"query","required":false,"description":"Only the page properties with this ID. Leave it out for all page properties of a page.","schema":{"type":"string","minLength":1,"maxLength":100}},{"name":"columns","in":"query","required":false,"description":"Property names to show as columns, separated by commas, up to 30. Leave it out for the names used on the listed pages. Names are compared without case.","schema":{"type":"string","maxLength":6030}},{"name":"sortBy","in":"query","required":false,"description":"Sort by the value of this property. Leave it out to sort by title. Pages without the property come last.","schema":{"type":"string","minLength":1,"maxLength":200}},{"name":"reverse","in":"query","required":false,"description":"`true` sorts from Z to A.","schema":{"default":"false","type":"string","enum":["true","false"]}},{"name":"pageSize","in":"query","required":false,"description":"Number of pages per page of results, 1 to 100.","schema":{"default":30,"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"description":"Number of pages to skip, for the next pages of results.","schema":{"default":0,"type":"integer","minimum":0,"maximum":1000000}}],"responses":{"200":{"description":"A page of the report.","content":{"application/json":{"schema":{"type":"object","properties":{"columns":{"type":"array","items":{"type":"string","description":"Property name."},"description":"Columns in the order of the cells."},"keys":{"type":"array","items":{"type":"string","description":"Property name."},"description":"Property names used on the pages that match, as choices for the columns."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of matching pages the caller can read."},"rows":{"type":"array","items":{"type":"object","properties":{"page":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the page."},"title":{"type":"string","description":"Title of the page."},"path":{"type":"string","description":"Path of the page in the web interface."},"spaceId":{"type":"string","format":"uuid","description":"Space of the page."}},"required":["id","title","path","spaceId"],"additionalProperties":false,"description":"The page."},"creator":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who created the page, or null when the caller may not see that person."},"labels":{"type":"array","items":{"type":"string","description":"A label."},"description":"Labels of the page."},"cells":{"type":"array","items":{"anyOf":[{"type":"array","items":{"description":"A paragraph or list as ProseMirror JSON.","$ref":"#/components/schemas/Schema113ae44d8375"}},{"type":"null"}],"description":"Value of the property as ProseMirror blocks: paragraphs and lists with links, mentions, dates and status."},"description":"One value per column, or null when the page does not have the property."}},"required":["page","creator","labels","cells"],"additionalProperties":false,"description":"A page with its properties."},"description":"Pages in the requested order."},"references":{"type":"object","properties":{"people":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","description":"Name of the person."},"description":"Names of mentioned people the caller may see, by account ID."},"pictures":{"description":"Profile pictures of the people in `people` that have one, by account ID. The picture is at `/api/v1/accounts/{accountId}/picture`.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","description":"Version of the profile picture."}},"pages":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"title":{"type":"string","description":"Title, or empty without access."},"spaceKey":{"type":"string","description":"Key of the page's space, or empty without access."},"kind":{"type":"string","description":"Kind of the item."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the item in the addresses of the app, or null without access."},"accessible":{"type":"boolean","description":"Whether the caller can open the page."},"inTrash":{"type":"boolean","description":"Whether the page is in the trash. Then only the title is given, as `In trash`."}},"required":["title","spaceKey","kind","number","accessible","inTrash"],"additionalProperties":false,"description":"A linked page."},"description":"Linked pages by ID."},"topics":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"title":{"type":"string","description":"Title of the running topic."},"status":{"type":"string","description":"Whether the topic is still open. New values can be added in later versions; handle unknown values.","x-extensible-enum":["open","closed"]}},"required":["title","status"],"additionalProperties":false,"description":"A running topic."},"description":"Running topics that topic updates and decisions in the document refer to, by ID, as far as the caller may see them."},"tooLargeImages":{"type":"array","items":{"type":"string","format":"uuid","description":"ID of an attachment."},"description":"Images in the document with more than 100 megapixels, as far as the caller may see them. They have no smaller version and are shown as a file that opens in full size."}},"required":["people","pages","topics","tooLargeImages"],"additionalProperties":false,"description":"What mentions and page links in the document point to, as far as the caller may see it."}},"required":["columns","keys","total","rows","references"],"additionalProperties":false,"description":"A page of a page properties report."},"example":{"columns":["Owner","Uplink"],"keys":["Owner","Uplink","Switches"],"total":1,"rows":[{"page":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5c11","title":"Site Graz","path":"/spaces/ITOPS/pages/1042/site-graz","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10"},"creator":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"labels":["site"],"cells":[[{"type":"paragraph","content":[{"type":"mention","attrs":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20"}}]}],[{"type":"paragraph","content":[{"type":"text","text":"1 Gbit/s fibre"}]}]]}],"references":{"people":{"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20":"Anna Berger"},"pages":{},"topics":{},"tooLargeImages":[]}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/reviews/mine":{"get":{"operationId":"reviews.mine","summary":"List the caller's articles to review","description":"Lists knowledge base articles the caller owns and may edit that need a review, for the personal home page.\n\nRequires the permission `instance.content.view` on the instance.","tags":["Knowledge base reviews"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"200":{"description":"The articles.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the article."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the article in the addresses of the app."},"title":{"type":"string","description":"Title of the article."},"type":{"anyOf":[{"type":"string","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values."},"spaceKey":{"type":"string","description":"Key of the knowledge base."},"spaceName":{"type":"string","description":"Name of the knowledge base."},"dueAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the review is due, or null. ISO 8601 timestamp in UTC."},"sourceChangedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When a source page changed after the last review, or null. ISO 8601 timestamp in UTC."},"state":{"type":"string","enum":["overdue","sourceChanged","dueSoon","current","off"],"description":"`overdue`: the interval has passed. `sourceChanged`: a source page changed since the last review. `dueSoon`: due within 30 days. `current`: reviewed within the interval. `off`: no interval applies."}},"required":["id","number","title","type","spaceKey","spaceName","dueAt","sourceChangedAt","state"],"additionalProperties":false,"description":"An article of the caller that needs a review."},"description":"Up to 20 articles, the most urgent first."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of all such articles."}},"required":["items","total"],"additionalProperties":false,"description":"Articles the caller owns that are due, due within 30 days or whose source page changed."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a50","number":4711,"title":"Set up the VPN at home","type":"howTo","spaceKey":"ITOPS","spaceName":"IT Operations","dueAt":"2026-10-02T09:00:00.000Z","sourceChangedAt":null,"state":"overdue"}],"total":1}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/service-accounts/{serviceAccountId}":{"get":{"operationId":"serviceAccounts.get","summary":"Get a service account","description":"Returns a service account.\n\nRequires the permission `serviceAccount.view` on the serviceAccount in `serviceAccountId`.","tags":["Service accounts"],"x-lunedo-permission":{"action":"serviceAccount.view","resource":"serviceAccount","parameter":"serviceAccountId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"serviceAccountId","in":"path","required":true,"description":"ID of the service account.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The service account.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the service account. Use it as account ID in role assignments and groups."},"organizationId":{"type":"string","format":"uuid","description":"ID of the organization that owns the service account."},"name":{"type":"string","description":"Display name, 1 to 200 characters."},"description":{"type":"string","description":"What the service account is for, up to 1000 characters."},"state":{"type":"string","description":"`active` or `deactivated`."},"responsibleAccountIds":{"type":"array","items":{"type":"string","format":"uuid","description":"ID of a responsible member."},"description":"Members who receive reminders and notices about the service account. They grant no permissions and limit none."},"unattended":{"type":"boolean","description":"True when the service account has no responsible person. Its permissions stay unchanged."},"createdAt":{"type":"string","format":"date-time","description":"When the service account was created. ISO 8601 timestamp in UTC."}},"required":["id","organizationId","name","description","state","responsibleAccountIds","unattended","createdAt"],"additionalProperties":false,"description":"An account for scripts and integrations, without password or sign-in."},"example":{"id":"01929b1f-3da0-7d84-b5a1-9c8d7e6fb0c1","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","name":"Release bot","description":"Publishes release notes","state":"active","responsibleAccountIds":["01929b1e-8d4b-7e3f-a05c-4d3e2f1a6b7c"],"unattended":false,"createdAt":"2026-10-01T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"patch":{"operationId":"serviceAccounts.update","summary":"Change a service account","description":"Changes name, description or the responsible people, who must be active members. Responsible people receive reminders and notices; they do not change permissions.\n\nRequires the permission `serviceAccount.manage` on the serviceAccount in `serviceAccountId`.","tags":["Service accounts"],"x-lunedo-permission":{"action":"serviceAccount.manage","resource":"serviceAccount","parameter":"serviceAccountId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"serviceAccountId","in":"path","required":true,"description":"ID of the service account.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"New display name.","type":"string","minLength":1,"maxLength":200},"description":{"description":"New description.","type":"string","maxLength":1000},"responsibleAccountIds":{"description":"New list of responsible members. Replaces the old list.","maxItems":20,"type":"array","items":{"type":"string","format":"uuid"}}},"additionalProperties":false,"description":"Fields to change."},"example":{"responsibleAccountIds":["01929b1e-8d4b-7e3f-a05c-4d3e2f1a6b7c"]}}}},"responses":{"200":{"description":"The changed service account.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the service account. Use it as account ID in role assignments and groups."},"organizationId":{"type":"string","format":"uuid","description":"ID of the organization that owns the service account."},"name":{"type":"string","description":"Display name, 1 to 200 characters."},"description":{"type":"string","description":"What the service account is for, up to 1000 characters."},"state":{"type":"string","description":"`active` or `deactivated`."},"responsibleAccountIds":{"type":"array","items":{"type":"string","format":"uuid","description":"ID of a responsible member."},"description":"Members who receive reminders and notices about the service account. They grant no permissions and limit none."},"unattended":{"type":"boolean","description":"True when the service account has no responsible person. Its permissions stay unchanged."},"createdAt":{"type":"string","format":"date-time","description":"When the service account was created. ISO 8601 timestamp in UTC."}},"required":["id","organizationId","name","description","state","responsibleAccountIds","unattended","createdAt"],"additionalProperties":false,"description":"An account for scripts and integrations, without password or sign-in."},"example":{"id":"01929b1f-3da0-7d84-b5a1-9c8d7e6fb0c1","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","name":"Release bot","description":"Publishes release notes","state":"active","responsibleAccountIds":["01929b1e-8d4b-7e3f-a05c-4d3e2f1a6b7c"],"unattended":false,"createdAt":"2026-10-01T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidResponsible`: The responsible person is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidResponsible":{"value":{"type":"urn:lunedo:problem:invalidResponsible","title":"The responsible person is not valid","status":400,"code":"invalidResponsible"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/service-accounts/{serviceAccountId}/deactivate":{"post":{"operationId":"serviceAccounts.deactivate","summary":"Deactivate a service account","description":"Deactivates the service account and revokes all its tokens at once.\n\nRequires the permission `serviceAccount.manage` on the serviceAccount in `serviceAccountId`.","tags":["Service accounts"],"x-lunedo-permission":{"action":"serviceAccount.manage","resource":"serviceAccount","parameter":"serviceAccountId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"serviceAccountId","in":"path","required":true,"description":"ID of the service account.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The number of revoked tokens.","content":{"application/json":{"schema":{"type":"object","properties":{"revokedTokens":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of tokens revoked with the deactivation."}},"required":["revokedTokens"],"additionalProperties":false,"description":"Result of the deactivation."},"example":{"revokedTokens":2}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/shared-with-me":{"get":{"operationId":"pageAccess.sharedWithMe","summary":"List pages shared with you","description":"Lists the pages that someone shared with the caller or one of their groups, newest first. Pages the caller can no longer view are left out.\n\nRequires the permission `instance.content.view` on the instance. Needs a signed-in session; API tokens are refused.","tags":["Page access"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"sessionCookie":[]}],"responses":{"200":{"description":"The pages.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"ID of the page."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the page in the addresses of the app."},"title":{"type":"string","description":"Title of the page."},"kind":{"type":"string","description":"Kind of the item. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","blogPost"]},"role":{"type":"string","enum":["reader","commenter","editor"],"description":"`reader` reads, `commenter` also comments, `editor` also edits, moves and deletes."},"includeDescendants":{"type":"boolean","description":"Whether the pages below are shared as well."},"sharedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who shared the page."},"sharedAt":{"type":"string","format":"date-time","description":"When the page was shared. ISO 8601 timestamp in UTC."},"spaceKey":{"type":"string","description":"Key of the space; empty when the caller has no access to the space."},"spaceName":{"type":"string","description":"Name of the space; empty when the caller has no access to the space."}},"required":["itemId","number","title","kind","role","includeDescendants","sharedBy","sharedAt","spaceKey","spaceName"],"additionalProperties":false,"description":"A page shared with the caller or one of their groups."},"description":"Shared pages, newest first."},"example":[{"itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","number":1042,"title":"VPN access for remote staff","kind":"page","role":"reader","includeDescendants":false,"sharedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a21","name":"Lukas Hofer"},"sharedAt":"2026-10-01T09:30:00.000Z","spaceKey":"","spaceName":""}]}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}}}}},"/api/v1/space-keys/{key}":{"get":{"operationId":"spaces.resolve","summary":"Find a space by key","description":"Returns the space that uses the key, or that used it before a key change. Spaces the caller cannot read are not found.\n\nRequires the permission `instance.content.view` on the instance.","tags":["Spaces"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"key","in":"path","required":true,"description":"Key of a space, or a key it had before.","schema":{"type":"string","maxLength":20}}],"responses":{"200":{"description":"The space.","content":{"application/json":{"schema":{"type":"object","properties":{"space":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space, 2 to 10 letters or digits. It appears in addresses."},"type":{"type":"string","description":"Type of the space: `standard` for pages, blog posts, meetings and whiteboards, or `knowledgeBase` for articles in categories. Chosen at creation. New values can be added in later versions; handle unknown values.","x-extensible-enum":["standard","knowledgeBase"]},"audience":{"anyOf":[{"type":"string","description":"Who may read a knowledge base: `public` (everyone, also without signing in, once the portal exists; in Lunedo all internal users), `signedIn` (all internal users of the instance), `groups` (members of the groups that hold the reader role) or `portal` (portal accounts; in Lunedo only holders of a role). Categories and articles can narrow it with view restrictions, never widen it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["public","signedIn","groups","portal"]},{"type":"null"}],"description":"Who may read the knowledge base, or null for other spaces."},"name":{"type":"string","description":"Name of the space. Empty for a personal space that has no name of its own."},"displayName":{"type":"string","description":"Name to show: the name of the space, or for a personal space without a name of its own \"Personal space of\" and the owner's name, in the owner's language."},"description":{"type":"string","description":"Short description, up to 1000 characters."},"visibility":{"type":"string","enum":["private","organization","instance"],"description":"Who can read the space besides its holders: `private` (only holders), `organization` (every member of the organization) or `instance` (every internal user of the instance)."},"discoverable":{"type":"boolean","description":"Whether members of the organization can find the space and ask for access without reading it."},"confidential":{"type":"boolean","description":"Whether the space is confidential: only its members can read it, and administrators cannot give themselves or others access. Chosen at creation."},"oneOnOne":{"type":"boolean","description":"Whether the space holds a one-on-one."},"quarantined":{"type":"boolean","description":"Whether the space holds an import that is not accepted yet. Only the importing administrator and the reviewers can read it."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization the space belongs to, or null for a personal space."},"organizationName":{"description":"Name of the organization, or null for a personal space.","type":["string","null"]},"personal":{"type":"boolean","description":"Whether this is a personal space."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of a personal space, or null."},"ownerName":{"description":"Name of the owner of a personal space, or null.","type":["string","null"]},"overviewItemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The overview page of the space, or null for a knowledge base."},"overviewItemNumber":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the overview page in the addresses of the app, or null for a knowledge base."},"archived":{"type":"boolean","description":"Whether the space is archived. Archived spaces are read-only."},"exportEnabled":{"type":"boolean","description":"Whether pages and the space can be exported. Space administrators turn export off and on; it applies to everyone. Turning it off does not prevent copying content."},"createdAt":{"type":"string","format":"date-time","description":"When the space was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the settings of the space last changed. ISO 8601 timestamp in UTC."},"role":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"The caller's role in the space, or null."},"mayExport":{"type":"boolean","description":"Whether the caller may export the whole space and pages with their subpages while export is turned on: space administrators, and organization administrators with access to the space outside confidential spaces. Every reader can export single pages."}},"required":["id","key","type","audience","name","displayName","description","visibility","discoverable","confidential","oneOnOne","quarantined","organizationId","organizationName","personal","ownerId","ownerName","overviewItemId","overviewItemNumber","archived","exportEnabled","createdAt","updatedAt","role","mayExport"],"additionalProperties":false,"description":"A space with the caller's role."},"redirected":{"type":"boolean","description":"Whether the key is an earlier key of the space."}},"required":["space","redirected"],"additionalProperties":false,"description":"The space a key leads to."},"example":{"space":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","key":"ITOPS","type":"standard","audience":null,"name":"IT Operations","displayName":"IT Operations","description":"Runbooks and how-tos of the IT team","visibility":"organization","discoverable":false,"confidential":false,"oneOnOne":false,"quarantined":false,"organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","organizationName":"Example Inc.","personal":false,"ownerId":null,"ownerName":null,"overviewItemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a11","overviewItemNumber":1001,"archived":false,"exportEnabled":true,"createdAt":"2026-10-05T08:00:00.000Z","updatedAt":"2026-10-05T08:00:00.000Z","role":"reader","mayExport":false},"redirected":false}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces":{"get":{"operationId":"spaces.list","summary":"List spaces","description":"Lists the spaces the caller can read, ordered by name. Archived spaces are listed only when asked for. API tokens see the spaces their scopes reach.\n\nRequires the permission `instance.content.view` on the instance.","tags":["Spaces"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}},{"name":"q","in":"query","required":false,"description":"Only spaces whose name, key or description contain this text.","schema":{"type":"string","maxLength":200}},{"name":"archived","in":"query","required":false,"description":"`true` lists only archived spaces. Without it, only spaces that are not archived are listed.","schema":{"type":"string","enum":["true","false"]}},{"name":"organizationId","in":"query","required":false,"description":"Only spaces of this organization.","schema":{"type":"string","format":"uuid"}},{"name":"oneOnOne","in":"query","required":false,"description":"`true` lists only the caller's one-on-ones. Without it, one-on-ones are left out.","schema":{"type":"string","enum":["true","false"]}},{"name":"role","in":"query","required":false,"description":"Only spaces where the caller holds at least this role, for example `editor` for the spaces the caller can create content in.","schema":{"type":"string","enum":["reader","commenter","editor","admin"]}},{"name":"type","in":"query","required":false,"description":"Only spaces of this type.","schema":{"type":"string","enum":["standard","knowledgeBase"]}}],"responses":{"200":{"description":"Readable spaces.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space, 2 to 10 letters or digits. It appears in addresses."},"type":{"type":"string","description":"Type of the space: `standard` for pages, blog posts, meetings and whiteboards, or `knowledgeBase` for articles in categories. Chosen at creation. New values can be added in later versions; handle unknown values.","x-extensible-enum":["standard","knowledgeBase"]},"audience":{"anyOf":[{"type":"string","description":"Who may read a knowledge base: `public` (everyone, also without signing in, once the portal exists; in Lunedo all internal users), `signedIn` (all internal users of the instance), `groups` (members of the groups that hold the reader role) or `portal` (portal accounts; in Lunedo only holders of a role). Categories and articles can narrow it with view restrictions, never widen it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["public","signedIn","groups","portal"]},{"type":"null"}],"description":"Who may read the knowledge base, or null for other spaces."},"name":{"type":"string","description":"Name of the space. Empty for a personal space that has no name of its own."},"displayName":{"type":"string","description":"Name to show: the name of the space, or for a personal space without a name of its own \"Personal space of\" and the owner's name, in the owner's language."},"description":{"type":"string","description":"Short description, up to 1000 characters."},"visibility":{"type":"string","enum":["private","organization","instance"],"description":"Who can read the space besides its holders: `private` (only holders), `organization` (every member of the organization) or `instance` (every internal user of the instance)."},"discoverable":{"type":"boolean","description":"Whether members of the organization can find the space and ask for access without reading it."},"confidential":{"type":"boolean","description":"Whether the space is confidential: only its members can read it, and administrators cannot give themselves or others access. Chosen at creation."},"oneOnOne":{"type":"boolean","description":"Whether the space holds a one-on-one."},"quarantined":{"type":"boolean","description":"Whether the space holds an import that is not accepted yet. Only the importing administrator and the reviewers can read it."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization the space belongs to, or null for a personal space."},"organizationName":{"description":"Name of the organization, or null for a personal space.","type":["string","null"]},"personal":{"type":"boolean","description":"Whether this is a personal space."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of a personal space, or null."},"ownerName":{"description":"Name of the owner of a personal space, or null.","type":["string","null"]},"overviewItemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The overview page of the space, or null for a knowledge base."},"overviewItemNumber":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the overview page in the addresses of the app, or null for a knowledge base."},"archived":{"type":"boolean","description":"Whether the space is archived. Archived spaces are read-only."},"exportEnabled":{"type":"boolean","description":"Whether pages and the space can be exported. Space administrators turn export off and on; it applies to everyone. Turning it off does not prevent copying content."},"createdAt":{"type":"string","format":"date-time","description":"When the space was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the settings of the space last changed. ISO 8601 timestamp in UTC."}},"required":["id","key","type","audience","name","displayName","description","visibility","discoverable","confidential","oneOnOne","quarantined","organizationId","organizationName","personal","ownerId","ownerName","overviewItemId","overviewItemNumber","archived","exportEnabled","createdAt","updatedAt"],"additionalProperties":false,"description":"A space."},"description":"Spaces, ordered by name."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"One page of results."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","key":"ITOPS","type":"standard","audience":null,"name":"IT Operations","displayName":"IT Operations","description":"Runbooks and how-tos of the IT team","visibility":"organization","discoverable":false,"confidential":false,"oneOnOne":false,"quarantined":false,"organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","organizationName":"Example Inc.","personal":false,"ownerId":null,"ownerName":null,"overviewItemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a11","overviewItemNumber":1001,"archived":false,"exportEnabled":true,"createdAt":"2026-10-05T08:00:00.000Z","updatedAt":"2026-10-05T08:00:00.000Z"}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}":{"get":{"operationId":"spaces.get","summary":"Get a space","description":"Returns the space with the caller's role in it.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The space.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space, 2 to 10 letters or digits. It appears in addresses."},"type":{"type":"string","description":"Type of the space: `standard` for pages, blog posts, meetings and whiteboards, or `knowledgeBase` for articles in categories. Chosen at creation. New values can be added in later versions; handle unknown values.","x-extensible-enum":["standard","knowledgeBase"]},"audience":{"anyOf":[{"type":"string","description":"Who may read a knowledge base: `public` (everyone, also without signing in, once the portal exists; in Lunedo all internal users), `signedIn` (all internal users of the instance), `groups` (members of the groups that hold the reader role) or `portal` (portal accounts; in Lunedo only holders of a role). Categories and articles can narrow it with view restrictions, never widen it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["public","signedIn","groups","portal"]},{"type":"null"}],"description":"Who may read the knowledge base, or null for other spaces."},"name":{"type":"string","description":"Name of the space. Empty for a personal space that has no name of its own."},"displayName":{"type":"string","description":"Name to show: the name of the space, or for a personal space without a name of its own \"Personal space of\" and the owner's name, in the owner's language."},"description":{"type":"string","description":"Short description, up to 1000 characters."},"visibility":{"type":"string","enum":["private","organization","instance"],"description":"Who can read the space besides its holders: `private` (only holders), `organization` (every member of the organization) or `instance` (every internal user of the instance)."},"discoverable":{"type":"boolean","description":"Whether members of the organization can find the space and ask for access without reading it."},"confidential":{"type":"boolean","description":"Whether the space is confidential: only its members can read it, and administrators cannot give themselves or others access. Chosen at creation."},"oneOnOne":{"type":"boolean","description":"Whether the space holds a one-on-one."},"quarantined":{"type":"boolean","description":"Whether the space holds an import that is not accepted yet. Only the importing administrator and the reviewers can read it."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization the space belongs to, or null for a personal space."},"organizationName":{"description":"Name of the organization, or null for a personal space.","type":["string","null"]},"personal":{"type":"boolean","description":"Whether this is a personal space."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of a personal space, or null."},"ownerName":{"description":"Name of the owner of a personal space, or null.","type":["string","null"]},"overviewItemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The overview page of the space, or null for a knowledge base."},"overviewItemNumber":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the overview page in the addresses of the app, or null for a knowledge base."},"archived":{"type":"boolean","description":"Whether the space is archived. Archived spaces are read-only."},"exportEnabled":{"type":"boolean","description":"Whether pages and the space can be exported. Space administrators turn export off and on; it applies to everyone. Turning it off does not prevent copying content."},"createdAt":{"type":"string","format":"date-time","description":"When the space was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the settings of the space last changed. ISO 8601 timestamp in UTC."},"role":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"The caller's role in the space, or null."},"mayExport":{"type":"boolean","description":"Whether the caller may export the whole space and pages with their subpages while export is turned on: space administrators, and organization administrators with access to the space outside confidential spaces. Every reader can export single pages."}},"required":["id","key","type","audience","name","displayName","description","visibility","discoverable","confidential","oneOnOne","quarantined","organizationId","organizationName","personal","ownerId","ownerName","overviewItemId","overviewItemNumber","archived","exportEnabled","createdAt","updatedAt","role","mayExport"],"additionalProperties":false,"description":"A space with the caller's role."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","key":"ITOPS","type":"standard","audience":null,"name":"IT Operations","displayName":"IT Operations","description":"Runbooks and how-tos of the IT team","visibility":"organization","discoverable":false,"confidential":false,"oneOnOne":false,"quarantined":false,"organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","organizationName":"Example Inc.","personal":false,"ownerId":null,"ownerName":null,"overviewItemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a11","overviewItemNumber":1001,"archived":false,"exportEnabled":true,"createdAt":"2026-10-05T08:00:00.000Z","updatedAt":"2026-10-05T08:00:00.000Z","role":"editor","mayExport":false}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"patch":{"operationId":"spaces.update","summary":"Change a space","description":"Renames a space or changes its description. Both changes are audited.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"New name, 1 to 100 characters.","type":"string","maxLength":100},"description":{"description":"New description, up to 1000 characters.","type":"string","maxLength":1000},"discoverable":{"description":"Whether members of the organization can find the space and ask for access. Not for personal spaces.","type":"boolean"}},"additionalProperties":false,"description":"Fields to change."},"example":{"description":"Runbooks, how-tos and contacts of the IT team"}}}},"responses":{"200":{"description":"The changed space.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space, 2 to 10 letters or digits. It appears in addresses."},"type":{"type":"string","description":"Type of the space: `standard` for pages, blog posts, meetings and whiteboards, or `knowledgeBase` for articles in categories. Chosen at creation. New values can be added in later versions; handle unknown values.","x-extensible-enum":["standard","knowledgeBase"]},"audience":{"anyOf":[{"type":"string","description":"Who may read a knowledge base: `public` (everyone, also without signing in, once the portal exists; in Lunedo all internal users), `signedIn` (all internal users of the instance), `groups` (members of the groups that hold the reader role) or `portal` (portal accounts; in Lunedo only holders of a role). Categories and articles can narrow it with view restrictions, never widen it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["public","signedIn","groups","portal"]},{"type":"null"}],"description":"Who may read the knowledge base, or null for other spaces."},"name":{"type":"string","description":"Name of the space. Empty for a personal space that has no name of its own."},"displayName":{"type":"string","description":"Name to show: the name of the space, or for a personal space without a name of its own \"Personal space of\" and the owner's name, in the owner's language."},"description":{"type":"string","description":"Short description, up to 1000 characters."},"visibility":{"type":"string","enum":["private","organization","instance"],"description":"Who can read the space besides its holders: `private` (only holders), `organization` (every member of the organization) or `instance` (every internal user of the instance)."},"discoverable":{"type":"boolean","description":"Whether members of the organization can find the space and ask for access without reading it."},"confidential":{"type":"boolean","description":"Whether the space is confidential: only its members can read it, and administrators cannot give themselves or others access. Chosen at creation."},"oneOnOne":{"type":"boolean","description":"Whether the space holds a one-on-one."},"quarantined":{"type":"boolean","description":"Whether the space holds an import that is not accepted yet. Only the importing administrator and the reviewers can read it."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization the space belongs to, or null for a personal space."},"organizationName":{"description":"Name of the organization, or null for a personal space.","type":["string","null"]},"personal":{"type":"boolean","description":"Whether this is a personal space."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of a personal space, or null."},"ownerName":{"description":"Name of the owner of a personal space, or null.","type":["string","null"]},"overviewItemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The overview page of the space, or null for a knowledge base."},"overviewItemNumber":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the overview page in the addresses of the app, or null for a knowledge base."},"archived":{"type":"boolean","description":"Whether the space is archived. Archived spaces are read-only."},"exportEnabled":{"type":"boolean","description":"Whether pages and the space can be exported. Space administrators turn export off and on; it applies to everyone. Turning it off does not prevent copying content."},"createdAt":{"type":"string","format":"date-time","description":"When the space was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the settings of the space last changed. ISO 8601 timestamp in UTC."}},"required":["id","key","type","audience","name","displayName","description","visibility","discoverable","confidential","oneOnOne","quarantined","organizationId","organizationName","personal","ownerId","ownerName","overviewItemId","overviewItemNumber","archived","exportEnabled","createdAt","updatedAt"],"additionalProperties":false,"description":"A space."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","key":"ITOPS","type":"standard","audience":null,"name":"IT Operations","displayName":"IT Operations","description":"Runbooks and how-tos of the IT team","visibility":"organization","discoverable":false,"confidential":false,"oneOnOne":false,"quarantined":false,"organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","organizationName":"Example Inc.","personal":false,"ownerId":null,"ownerName":null,"overviewItemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a11","overviewItemNumber":1001,"archived":false,"exportEnabled":true,"createdAt":"2026-10-05T08:00:00.000Z","updatedAt":"2026-10-05T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidSpaceDescription`: The space description is too long. `invalidSpaceName`: The space name is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidSpaceDescription":{"value":{"type":"urn:lunedo:problem:invalidSpaceDescription","title":"The space description is too long","status":400,"code":"invalidSpaceDescription"}},"invalidSpaceName":{"value":{"type":"urn:lunedo:problem:invalidSpaceName","title":"The space name is not valid","status":400,"code":"invalidSpaceName"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/access-requests":{"get":{"operationId":"accessRequests.forSpace","summary":"List open access requests of a space","description":"Lists the open requests the caller can decide: all of them for space admins, those for their restricted pages for the people who restricted them.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Access requests"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Open requests, oldest first.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the request."},"requester":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]},"email":{"description":"E-mail address, when the caller may see it.","type":["string","null"]}},"required":["id","name","email"],"additionalProperties":false,"description":"Who asks."},"target":{"type":"string","description":"Whether the request is for a whole space or for a page. New values can be added in later versions; handle unknown values.","x-extensible-enum":["space","page"]},"spaceId":{"anyOf":[{"type":"string","format":"uuid","description":"The space."},{"type":"null"}],"description":"The space, or null when the requester cannot see the page the request is for."},"spaceName":{"type":"string","description":"Name of the space; empty when the requester cannot see it."},"itemId":{"anyOf":[{"type":"string","format":"uuid","description":"The page."},{"type":"null"}],"description":"The page; null for the whole space and when the requester cannot see the page."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the page in the addresses of the app."},{"type":"null"}],"description":"Number of the page in the addresses of the app, when the caller may see its title; null for the whole space."},"itemTitle":{"description":"Title of the page, when the caller may see it.","type":["string","null"]},"message":{"type":"string","description":"Message of the requester."},"status":{"type":"string","description":"`satisfied` means the person got access another way. New values can be added in later versions; handle unknown values.","x-extensible-enum":["open","approved","declined","withdrawn","satisfied"]},"role":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"]},{"type":"null"}],"description":"The role given when approved."},"decidedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who decided; null when the requester cannot see the page."},"decidedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When it was decided. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When it was sent. ISO 8601 timestamp in UTC."}},"required":["id","requester","target","spaceId","spaceName","itemId","number","itemTitle","message","status","role","decidedBy","decidedAt","createdAt"],"additionalProperties":false,"description":"A request for access to a space or page."},"description":"Open requests."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","requester":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a22","name":"Mia Kranz","email":"mia.kranz@example.org"},"target":"space","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a00","spaceName":"IT Operations","itemId":null,"number":null,"itemTitle":null,"message":"I take over the on-call duty next month.","status":"open","role":null,"decidedBy":null,"decidedAt":null,"createdAt":"2026-10-01T09:30:00.000Z"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"accessRequests.requestSpace","summary":"Ask for access to a space","description":"Asks the space admins for access to a discoverable space. A second request while one is open returns the open one.\n\nRequires the permission `instance.content.view` on the instance. Needs a signed-in session; API tokens are refused.","tags":["Access requests"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"default":"","description":"Why the access is needed, up to 1000 characters.","type":"string","maxLength":1000}},"additionalProperties":false,"description":"A request for access."},"example":{"message":"I take over the on-call duty next month."}}}},"responses":{"201":{"description":"The request.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the request."},"requester":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]},"email":{"description":"E-mail address, when the caller may see it.","type":["string","null"]}},"required":["id","name","email"],"additionalProperties":false,"description":"Who asks."},"target":{"type":"string","description":"Whether the request is for a whole space or for a page. New values can be added in later versions; handle unknown values.","x-extensible-enum":["space","page"]},"spaceId":{"anyOf":[{"type":"string","format":"uuid","description":"The space."},{"type":"null"}],"description":"The space, or null when the requester cannot see the page the request is for."},"spaceName":{"type":"string","description":"Name of the space; empty when the requester cannot see it."},"itemId":{"anyOf":[{"type":"string","format":"uuid","description":"The page."},{"type":"null"}],"description":"The page; null for the whole space and when the requester cannot see the page."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the page in the addresses of the app."},{"type":"null"}],"description":"Number of the page in the addresses of the app, when the caller may see its title; null for the whole space."},"itemTitle":{"description":"Title of the page, when the caller may see it.","type":["string","null"]},"message":{"type":"string","description":"Message of the requester."},"status":{"type":"string","description":"`satisfied` means the person got access another way. New values can be added in later versions; handle unknown values.","x-extensible-enum":["open","approved","declined","withdrawn","satisfied"]},"role":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"]},{"type":"null"}],"description":"The role given when approved."},"decidedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who decided; null when the requester cannot see the page."},"decidedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When it was decided. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When it was sent. ISO 8601 timestamp in UTC."}},"required":["id","requester","target","spaceId","spaceName","itemId","number","itemTitle","message","status","role","decidedBy","decidedAt","createdAt"],"additionalProperties":false,"description":"A request for access to a space or page."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","requester":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a22","name":"Mia Kranz","email":"mia.kranz@example.org"},"target":"space","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a00","spaceName":"IT Operations","itemId":null,"number":null,"itemTitle":null,"message":"I take over the on-call duty next month.","status":"open","role":null,"decidedBy":null,"decidedAt":null,"createdAt":"2026-10-01T09:30:00.000Z"}}}},"400":{"description":"`invalidInput`: The request is not valid. `messageTooLong`: The message is too long.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"messageTooLong":{"value":{"type":"urn:lunedo:problem:messageTooLong","title":"The message is too long","status":400,"code":"messageTooLong"}}}}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`alreadyHasAccess`: The person already has access.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"alreadyHasAccess":{"value":{"type":"urn:lunedo:problem:alreadyHasAccess","title":"The person already has access","status":409,"code":"alreadyHasAccess"}}}}}},"429":{"description":"`tooManyRequests`: Too many access requests today.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"tooManyRequests":{"value":{"type":"urn:lunedo:problem:tooManyRequests","title":"Too many access requests today","status":429,"code":"tooManyRequests"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/access/explain":{"get":{"operationId":"pageAccess.explainSpace","summary":"Explain why someone has access to a space","description":"Lists the roles that give the person access to the space and how they hold them.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Page access"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"accountId","in":"query","required":true,"description":"The person.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The explanation.","content":{"application/json":{"schema":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"The person."},"name":{"description":"Name, or null when hidden.","type":["string","null"]},"role":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"]},{"type":"null"}],"description":"What the person may do, or null for no access."},"reasons":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"Kind of reason. New values can be added in later versions; handle unknown values.","x-extensible-enum":["spaceRole","share","link"]},"role":{"description":"Role that the reason grants.","type":"string","enum":["reader","commenter","editor","admin"]},"via":{"type":"object","properties":{"type":{"type":"string","description":"How the role is held. New values can be added in later versions; handle unknown values.","x-extensible-enum":["account","group","organizationMembers","instanceUsers","visibility"]},"groupId":{"type":"string","format":"uuid","description":"The group."},"name":{"description":"Name of the group.","type":"string"},"visibility":{"description":"Visibility of the space that grants the role.","type":"string"}},"required":["type"],"additionalProperties":false,"description":"How a role in the space is held."},"itemId":{"type":"string","format":"uuid","description":"Page that was shared."},"itemTitle":{"description":"Its title, or null when the caller cannot see it.","type":["string","null"]},"inherited":{"description":"Whether the share comes from a page above.","type":"boolean"},"linkId":{"type":"string","format":"uuid","description":"The share link."},"scope":{"description":"Scope of the share link.","type":"string"},"inactive":{"type":"string","description":"Set when the entry is stored but grants nothing: `membershipEnded` means the person is no longer a member of the organization the space belongs to. It applies again if they become a member again. New values can be added in later versions; handle unknown values.","x-extensible-enum":["membershipEnded"]}},"required":["type"],"additionalProperties":false,"description":"Why a person has access, or an entry that has no effect."},"description":"Why: roles, shares and links."},"denial":{"description":"Why access is missing or narrower: `restricted`, `editRestricted`, `unpublished`, `inTrash`, `accountInactive` or `noAccess`.","type":["string","null"]},"restrictions":{"type":"array","items":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"Restricted page."},"title":{"description":"Its title, or null when hidden.","type":["string","null"]},"listed":{"type":"boolean","description":"Whether the person is on its access list."}},"required":["itemId","title","listed"],"additionalProperties":false,"description":"A view restriction that applies."},"description":"View restrictions on the page and above."},"editRestricted":{"anyOf":[{"type":"object","properties":{"listed":{"type":"boolean","description":"Whether the person may edit by the access list."}},"required":["listed"],"additionalProperties":false},{"type":"null"}],"description":"The edit restriction of the page, if any."},"published":{"type":"boolean","description":"Whether readers can see the page yet."}},"required":["accountId","name","role","reasons","denial","restrictions","editRestricted","published"],"additionalProperties":false,"description":"Why a person has or lacks access."},"example":{"accountId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a22","name":"Lukas Hofer","role":"reader","reasons":[{"type":"spaceRole","role":"reader","via":{"type":"group","groupId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a30","name":"IT Operations"}}],"denial":null,"restrictions":[],"editRestricted":null,"published":true}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `personNotFound`: The person does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"personNotFound":{"value":{"type":"urn:lunedo:problem:personNotFound","title":"The person does not exist","status":404,"code":"personNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/archive":{"get":{"operationId":"items.archived","summary":"List the archive of a space","description":"Lists the archived pages and folders of a space by title. Their descendants load through the list of children.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Pages"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Archived items.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the archived item."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the archived item in the addresses of the app."},"kind":{"type":"string","description":"Kind of the item. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title."},"hasChildren":{"type":"boolean","description":"Whether it has archived descendants."},"archivedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When it was archived. ISO 8601 timestamp in UTC."},"archivedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when the account no longer exists.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who archived it."}},"required":["id","number","kind","title","hasChildren","archivedAt","archivedBy"],"additionalProperties":false,"description":"An archived page or folder."},"description":"Archived items, by title."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"kind":"page","title":"Printer list 2024","hasChildren":false,"archivedAt":"2026-10-05T08:00:00.000Z","archivedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"}}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/archived":{"put":{"operationId":"trash.archiveSpace","summary":"Archive a space or bring it back","description":"An archived space is read-only and no longer appears in the default list of spaces. Its content keeps its versions and links.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Trash"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"archived":{"type":"boolean","description":"True to archive the space, false to bring it back."}},"required":["archived"],"additionalProperties":false,"description":"The archive state of the space."},"example":{"archived":true}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/article-changes":{"get":{"operationId":"articleApi.changes","summary":"List changed and removed articles","description":"Returns the articles of a knowledge base that the caller can read and that changed since `changedSince`, with their sections as HTML and text, and the numbers of articles removed since then. Without `changedSince` it returns every published article. Pages through a stable cursor.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Knowledge base articles"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}},{"name":"changedSince","in":"query","required":false,"description":"Only articles that changed after this moment, ISO 8601, with the numbers of articles removed since then. Leave it out for all published articles. At most 90 days back.","schema":{"type":"string","format":"date-time"}},{"name":"cursor","in":"query","required":false,"description":"Cursor from the previous page.","schema":{"type":"string","maxLength":500}},{"name":"limit","in":"query","required":false,"description":"Articles per page, 1 to 200.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}},{"name":"draft","in":"query","required":false,"description":"`true` returns the current drafts, also of unpublished articles, of the articles the caller may edit. Needs a token that may write drafts.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"The changes.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the article."},"spaceId":{"type":"string","format":"uuid","description":"ID of the knowledge base."},"title":{"type":"string","description":"Title of the article."},"type":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Type of the article, or null."},"number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the article. It is unique on the instance, shared with pages, folders, blog posts and whiteboards, and never reused. It stays when the article moves."},"slug":{"type":"string","description":"Short form of the title for addresses. The address of an article is `<number>-<slug>`."},"categoryPath":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the category."},"title":{"type":"string","description":"Title of the category."}},"required":["id","title"],"additionalProperties":false,"description":"A category."},"description":"Folders above the article from the top level down, as far as the caller can see them. Empty at the top level."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of the article, or null."},"ownerName":{"description":"Name of the owner, or null when the caller may not see it.","type":["string","null"]},"published":{"type":"boolean","description":"Whether the article was published. Only editors see unpublished articles."},"contentUpdatedAt":{"type":"string","format":"date-time","description":"When the content last changed. ISO 8601 timestamp in UTC."},"language":{"type":"string","description":"Language of the article."},"translationOf":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The original article when this is a translation, or null."},"translations":{"type":"array","items":{"type":"object","properties":{"language":{"type":"string","description":"Language as a two-letter code such as `de` or `en`."},"itemId":{"type":"string","format":"uuid","description":"ID of the translation."},"state":{"type":"string","enum":["original","current","outdated","unpublished","missing"],"description":"`original`: the article in the default language. `current`: published after its original. `outdated`: the original was published after it. `unpublished`: never published. `missing`: no translation yet."}},"required":["language","itemId","state"],"additionalProperties":false,"description":"A translation of the article."},"description":"Translations of an original article the caller can read. Empty for translations."},"spaceKey":{"type":"string","description":"Key of the knowledge base."},"lead":{"type":"string","description":"Short introduction below the title."},"templateId":{"description":"Template the article was created from, or null.","type":["string","null"]},"contactEmail":{"anyOf":[{"type":"string","maxLength":254},{"type":"null"}],"description":"Contact address that applies to the article, or null."},"version":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the published version that is returned, or null for a draft or an unpublished article."},"sections":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the section, such as `steps` or `cause`. It keeps its meaning in every language."},"title":{"type":"string","description":"Heading of the section."},"icon":{"description":"Name of a Lucide icon, or null.","type":["string","null"]},"text":{"type":"string","description":"Plain text of the section."},"html":{"type":"string","description":"Content of the section as HTML. Images point to their display version in the API, links to other articles to the portal."},"content":{"type":"array","items":{"$ref":"#/components/schemas/Schema113ae44d8375"},"description":"Content of the section as ProseMirror JSON nodes."}},"required":["key","title","icon","text","html","content"],"additionalProperties":false,"description":"A section of the article."},"description":"Semantic sections of the article in document order. Empty for an article written without sections."},"document":{"anyOf":[{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schemafbc378f59d82"},{"type":"null"}],"description":"Whole content as ProseMirror JSON, or null for an article that was never published."},"images":{"type":"array","items":{"type":"object","properties":{"attachmentId":{"type":"string","format":"uuid","description":"ID of the image file."},"name":{"type":"string","description":"File name."},"alt":{"type":"string","description":"Alternative text, empty when the author gave none."},"url":{"type":"string","description":"Address of the display version in the API; send the same token to fetch it."}},"required":["attachmentId","name","alt","url"],"additionalProperties":false,"description":"An image of the article."},"description":"Images in the content, in document order."},"draft":{"type":"boolean","description":"Whether this is the current draft instead of the published version."},"publishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the article was published for the first time, or null. ISO 8601 timestamp in UTC."},"versionPublishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the returned version was published, or null for a draft. ISO 8601 timestamp in UTC."},"lastReviewedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the article was last reviewed while a review interval applies, or null. ISO 8601 timestamp in UTC."},"portalUrl":{"description":"Address of the article in the portal, in its language, or null when it is not published.","type":["string","null"]}},"required":["id","spaceId","title","type","number","slug","categoryPath","ownerId","ownerName","published","contentUpdatedAt","language","translationOf","translations","spaceKey","lead","templateId","contactEmail","version","sections","document","images","draft","publishedAt","versionPublishedAt","lastReviewedAt","portalUrl"],"additionalProperties":false,"description":"An article with its sections, readable by programs."},"description":"New and changed articles, oldest change first."},"removed":{"type":"array","items":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"ID the article had."},"number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Number the article had, or null."},"language":{"description":"Language of the removed article or translation.","type":["string","null"]},"reason":{"type":"string","enum":["deleted","unpublished","moved"],"description":"`deleted`: in the trash or deleted. `unpublished`: no longer readable. `moved`: moved to another space."},"removedAt":{"type":"string","format":"date-time","description":"When it was removed. ISO 8601 timestamp in UTC."}},"required":["itemId","number","language","reason","removedAt"],"additionalProperties":false,"description":"An article that readers can no longer find under its number and language."},"description":"Removed articles. They are kept for 90 days."},"nextCursor":{"description":"Cursor for the next page, or null on the last page.","type":["string","null"]},"nextChangedSince":{"type":"string","format":"date-time","description":"Value to send as `changedSince` in the next sync. It lies a few minutes in the past, so changes that were saved at the same moment are not missed; articles can therefore appear twice and are best stored by ID. ISO 8601 timestamp in UTC."}},"required":["items","removed","nextCursor","nextChangedSince"],"additionalProperties":false,"description":"Changes of the articles of a knowledge base."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a61","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","title":"Set up the VPN connection","type":"howTo","number":1123,"slug":"set-up-the-vpn-connection","categoryPath":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","title":"IT"}],"ownerId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","ownerName":"Anna Weber","published":true,"contentUpdatedAt":"2026-10-05T08:00:00.000Z","language":"de","translationOf":null,"translations":[{"language":"en","itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a62","state":"outdated"}],"spaceKey":"HELP","lead":"Work from home with the company network.","templateId":"builtin:article-how-to","contactEmail":"it@example.org","version":3,"sections":[{"key":"steps","title":"Steps","icon":"list-ordered","text":"Open the VPN client.","html":"<p>Open the VPN client.</p>","content":[{"type":"paragraph","content":[{"type":"text","text":"Open the VPN client."}]}]}],"document":null,"images":[],"draft":false,"publishedAt":"2026-09-01T08:00:00.000Z","versionPublishedAt":"2026-10-05T08:00:00.000Z","lastReviewedAt":null,"portalUrl":"https://wiki.example.org/help/help/1123-set-up-the-vpn-connection"}],"removed":[{"itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a63","number":1098,"language":"de","reason":"deleted","removedAt":"2026-10-12T07:00:00.000Z"}],"nextCursor":null,"nextChangedSince":"2026-10-20T05:55:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `changedSinceTooOld`: Changes are known only for a limited time. `invalidCursor`: The cursor is not valid. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"changedSinceTooOld":{"value":{"type":"urn:lunedo:problem:changedSinceTooOld","title":"Changes are known only for a limited time","status":400,"code":"changedSinceTooOld"}},"invalidCursor":{"value":{"type":"urn:lunedo:problem:invalidCursor","title":"The cursor is not valid","status":400,"code":"invalidCursor"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`draftNotVisible`: Only editors see the draft. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"draftNotVisible":{"value":{"type":"urn:lunedo:problem:draftNotVisible","title":"Only editors see the draft","status":403,"code":"draftNotVisible"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notKnowledgeBase`: The space is not a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/articles":{"get":{"operationId":"knowledgeBases.articles","summary":"List the articles of a knowledge base","description":"Lists the articles the caller can read, most recently changed first.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}},{"name":"categoryId","in":"query","required":false,"description":"Only articles in this category and its subcategories.","schema":{"type":"string","format":"uuid"}},{"name":"topLevel","in":"query","required":false,"description":"`true` lists only articles outside every category.","schema":{"type":"string","enum":["true","false"]}},{"name":"type","in":"query","required":false,"description":"Only articles of this type; `none` for articles without a type.","schema":{"type":"string","enum":["howTo","troubleshooting","none"]}}],"responses":{"200":{"description":"Articles.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the article."},"spaceId":{"type":"string","format":"uuid","description":"ID of the knowledge base."},"title":{"type":"string","description":"Title of the article."},"type":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Type of the article, or null."},"number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the article. It is unique on the instance, shared with pages, folders, blog posts and whiteboards, and never reused. It stays when the article moves."},"slug":{"type":"string","description":"Short form of the title for addresses. The address of an article is `<number>-<slug>`."},"categoryPath":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the category."},"title":{"type":"string","description":"Title of the category."}},"required":["id","title"],"additionalProperties":false,"description":"A category."},"description":"Folders above the article from the top level down, as far as the caller can see them. Empty at the top level."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of the article, or null."},"ownerName":{"description":"Name of the owner, or null when the caller may not see it.","type":["string","null"]},"published":{"type":"boolean","description":"Whether the article was published. Only editors see unpublished articles."},"contentUpdatedAt":{"type":"string","format":"date-time","description":"When the content last changed. ISO 8601 timestamp in UTC."},"language":{"type":"string","description":"Language of the article."},"translationOf":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The original article when this is a translation, or null."},"translations":{"type":"array","items":{"type":"object","properties":{"language":{"type":"string","description":"Language as a two-letter code such as `de` or `en`."},"itemId":{"type":"string","format":"uuid","description":"ID of the translation."},"state":{"type":"string","enum":["original","current","outdated","unpublished","missing"],"description":"`original`: the article in the default language. `current`: published after its original. `outdated`: the original was published after it. `unpublished`: never published. `missing`: no translation yet."}},"required":["language","itemId","state"],"additionalProperties":false,"description":"A translation of the article."},"description":"Translations of an original article the caller can read. Empty for translations."}},"required":["id","spaceId","title","type","number","slug","categoryPath","ownerId","ownerName","published","contentUpdatedAt","language","translationOf","translations"],"additionalProperties":false,"description":"An article."},"description":"Articles, most recently changed first."},"nextCursor":{"description":"Cursor for the next page, or null on the last page. Pass it as `cursor`.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"One page of results."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a61","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","title":"Set up the VPN connection","type":"howTo","number":1123,"slug":"set-up-the-vpn-connection","categoryPath":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","title":"IT"}],"ownerId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","ownerName":"Anna Weber","published":true,"contentUpdatedAt":"2026-10-05T08:00:00.000Z","language":"de","translationOf":null,"translations":[{"language":"en","itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a62","state":"outdated"}]}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notKnowledgeBase`: The space is not a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"articleApi.create","summary":"Create an article","description":"Creates an article with its sections, category and type, or a translation of an article. It stays a draft unless `publish` is set and the caller may publish. Upload images afterwards and reference them in a draft.\n\nRequires the permission `space.createDraft` on the space in `spaceId`.","tags":["Knowledge base articles"],"x-lunedo-permission":{"action":"space.createDraft","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":255,"description":"Title of the article."},"lead":{"description":"Short introduction below the title.","type":"string","maxLength":1000},"type":{"description":"Type of the article, or null for none.","anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}]},"categoryId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Category or subcategory to place the article in, or null for the top level."},"sections":{"description":"Sections in order. They replace the whole content of the draft.","maxItems":50,"type":"array","items":{"type":"object","properties":{"key":{"type":"string","pattern":"^[a-z][a-zA-Z0-9]{0,39}$","description":"Key of the section, such as `steps` or `cause`."},"title":{"description":"Heading of the section.","type":"string","maxLength":255},"icon":{"description":"Name of a Lucide icon, or null.","anyOf":[{"type":"string","maxLength":60},{"type":"null"}]},"markdown":{"description":"Content as Markdown. Images uploaded to the article are referenced by their file name, for example `![Login screen](login.png)`.","type":"string","maxLength":500000},"content":{"description":"Content as ProseMirror JSON nodes instead of Markdown. Images reference `attachmentId`.","maxItems":10000,"type":"array","items":{"$ref":"#/components/schemas/Schema113ae44d8375"}}},"required":["key"],"additionalProperties":false,"description":"A section of the article."}},"versionNote":{"description":"Note shown in the history, for example who checked the content. Stored with the draft and used when it is published.","type":"string","maxLength":1000},"translationOf":{"type":"string","format":"uuid","description":"Original article when the new article is its translation."},"language":{"description":"Language of a translation. New articles without `translationOf` are in the default language.","type":"string"},"publish":{"default":false,"description":"Publish at once. Needs a token that may publish; otherwise the article stays a draft.","type":"boolean"}},"required":["title"],"additionalProperties":false,"description":"A new article."},"example":{"title":"Set up the VPN connection","type":"howTo","categoryId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","sections":[{"key":"steps","title":"Steps","markdown":"1. Open the VPN client.\n2. Sign in."}],"versionNote":"Checked by Anna Huber in the help assistant","publish":false}}}},"responses":{"201":{"description":"The new article.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the article."},"spaceId":{"type":"string","format":"uuid","description":"ID of the knowledge base."},"title":{"type":"string","description":"Title of the article."},"type":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Type of the article, or null."},"number":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the article. It is unique on the instance, shared with pages, folders, blog posts and whiteboards, and never reused. It stays when the article moves."},"slug":{"type":"string","description":"Short form of the title for addresses. The address of an article is `<number>-<slug>`."},"categoryPath":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the category."},"title":{"type":"string","description":"Title of the category."}},"required":["id","title"],"additionalProperties":false,"description":"A category."},"description":"Folders above the article from the top level down, as far as the caller can see them. Empty at the top level."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of the article, or null."},"ownerName":{"description":"Name of the owner, or null when the caller may not see it.","type":["string","null"]},"published":{"type":"boolean","description":"Whether the article was published. Only editors see unpublished articles."},"contentUpdatedAt":{"type":"string","format":"date-time","description":"When the content last changed. ISO 8601 timestamp in UTC."},"language":{"type":"string","description":"Language of the article."},"translationOf":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The original article when this is a translation, or null."},"translations":{"type":"array","items":{"type":"object","properties":{"language":{"type":"string","description":"Language as a two-letter code such as `de` or `en`."},"itemId":{"type":"string","format":"uuid","description":"ID of the translation."},"state":{"type":"string","enum":["original","current","outdated","unpublished","missing"],"description":"`original`: the article in the default language. `current`: published after its original. `outdated`: the original was published after it. `unpublished`: never published. `missing`: no translation yet."}},"required":["language","itemId","state"],"additionalProperties":false,"description":"A translation of the article."},"description":"Translations of an original article the caller can read. Empty for translations."},"spaceKey":{"type":"string","description":"Key of the knowledge base."},"lead":{"type":"string","description":"Short introduction below the title."},"templateId":{"description":"Template the article was created from, or null.","type":["string","null"]},"contactEmail":{"anyOf":[{"type":"string","maxLength":254},{"type":"null"}],"description":"Contact address that applies to the article, or null."},"version":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the published version that is returned, or null for a draft or an unpublished article."},"sections":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the section, such as `steps` or `cause`. It keeps its meaning in every language."},"title":{"type":"string","description":"Heading of the section."},"icon":{"description":"Name of a Lucide icon, or null.","type":["string","null"]},"text":{"type":"string","description":"Plain text of the section."},"html":{"type":"string","description":"Content of the section as HTML. Images point to their display version in the API, links to other articles to the portal."},"content":{"type":"array","items":{"$ref":"#/components/schemas/Schema113ae44d8375"},"description":"Content of the section as ProseMirror JSON nodes."}},"required":["key","title","icon","text","html","content"],"additionalProperties":false,"description":"A section of the article."},"description":"Semantic sections of the article in document order. Empty for an article written without sections."},"document":{"anyOf":[{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schemafbc378f59d82"},{"type":"null"}],"description":"Whole content as ProseMirror JSON, or null for an article that was never published."},"images":{"type":"array","items":{"type":"object","properties":{"attachmentId":{"type":"string","format":"uuid","description":"ID of the image file."},"name":{"type":"string","description":"File name."},"alt":{"type":"string","description":"Alternative text, empty when the author gave none."},"url":{"type":"string","description":"Address of the display version in the API; send the same token to fetch it."}},"required":["attachmentId","name","alt","url"],"additionalProperties":false,"description":"An image of the article."},"description":"Images in the content, in document order."},"draft":{"type":"boolean","description":"Whether this is the current draft instead of the published version."},"publishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the article was published for the first time, or null. ISO 8601 timestamp in UTC."},"versionPublishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the returned version was published, or null for a draft. ISO 8601 timestamp in UTC."},"lastReviewedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the article was last reviewed while a review interval applies, or null. ISO 8601 timestamp in UTC."},"portalUrl":{"description":"Address of the article in the portal, in its language, or null when it is not published.","type":["string","null"]}},"required":["id","spaceId","title","type","number","slug","categoryPath","ownerId","ownerName","published","contentUpdatedAt","language","translationOf","translations","spaceKey","lead","templateId","contactEmail","version","sections","document","images","draft","publishedAt","versionPublishedAt","lastReviewedAt","portalUrl"],"additionalProperties":false,"description":"An article with its sections, readable by programs."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a61","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","title":"Set up the VPN connection","type":"howTo","number":1123,"slug":"set-up-the-vpn-connection","categoryPath":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","title":"IT"}],"ownerId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","ownerName":"Anna Weber","published":true,"contentUpdatedAt":"2026-10-05T08:00:00.000Z","language":"de","translationOf":null,"translations":[{"language":"en","itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a62","state":"outdated"}],"spaceKey":"HELP","lead":"Work from home with the company network.","templateId":"builtin:article-how-to","contactEmail":"it@example.org","version":3,"sections":[{"key":"steps","title":"Steps","icon":"list-ordered","text":"Open the VPN client.","html":"<p>Open the VPN client.</p>","content":[{"type":"paragraph","content":[{"type":"text","text":"Open the VPN client."}]}]}],"document":null,"images":[],"draft":false,"publishedAt":"2026-09-01T08:00:00.000Z","versionPublishedAt":"2026-10-05T08:00:00.000Z","lastReviewedAt":null,"portalUrl":"https://wiki.example.org/help/help/1123-set-up-the-vpn-connection"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidDocument`: The document does not match the editor schema. `invalidInput`: The request is not valid. `invalidLanguage`: The language is not supported. `invalidNote`: The note is too long.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidDocument":{"value":{"type":"urn:lunedo:problem:invalidDocument","title":"The document does not match the editor schema","status":400,"code":"invalidDocument"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidLanguage":{"value":{"type":"urn:lunedo:problem:invalidLanguage","title":"The language is not supported","status":400,"code":"invalidLanguage"}},"invalidNote":{"value":{"type":"urn:lunedo:problem:invalidNote","title":"The note is too long","status":400,"code":"invalidNote"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `publishNotAllowed`: Publishing is not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"publishNotAllowed":{"value":{"type":"urn:lunedo:problem:publishNotAllowed","title":"Publishing is not allowed","status":403,"code":"publishNotAllowed"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`knowledgeBasePlacement`: Articles and categories are placed in categories. `languageNotEnabled`: The language is not enabled for the knowledge base. `notKnowledgeBase`: The space is not a knowledge base. `requiredSectionsEmpty`: Required sections are empty. `translationExists`: The article already has a translation into this language. `translationSource`: Only original articles can be translated.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"knowledgeBasePlacement":{"value":{"type":"urn:lunedo:problem:knowledgeBasePlacement","title":"Articles and categories are placed in categories","status":409,"code":"knowledgeBasePlacement"}},"languageNotEnabled":{"value":{"type":"urn:lunedo:problem:languageNotEnabled","title":"The language is not enabled for the knowledge base","status":409,"code":"languageNotEnabled"}},"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}},"requiredSectionsEmpty":{"value":{"type":"urn:lunedo:problem:requiredSectionsEmpty","title":"Required sections are empty","status":409,"code":"requiredSectionsEmpty"}},"translationExists":{"value":{"type":"urn:lunedo:problem:translationExists","title":"The article already has a translation into this language","status":409,"code":"translationExists"}},"translationSource":{"value":{"type":"urn:lunedo:problem:translationSource","title":"Only original articles can be translated","status":409,"code":"translationSource"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/blog":{"get":{"operationId":"blog.listSpace","summary":"List the blog of a space","description":"Lists the blog posts of a space: pinned posts first, then the newest. Editors also see drafts and scheduled posts.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Blog"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Cursor from `nextCursor` of the previous page.","schema":{"type":"string","maxLength":500}},{"name":"limit","in":"query","required":false,"description":"Maximum number of posts, 1 to 100.","schema":{"default":30,"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"The posts.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the blog post in the addresses of the app."},"spaceId":{"type":"string","format":"uuid","description":"Space of the post."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."},"title":{"type":"string","description":"Title as readers see it."},"excerpt":{"type":"string","description":"Short summary shown in lists."},"labels":{"type":"array","items":{"type":"string","description":"A label."},"description":"Labels, sorted."},"author":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who wrote the post, or null."},"published":{"type":"boolean","description":"Whether the post was published. Unpublished posts are visible only to editors."},"publishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post was first published, or null. ISO 8601 timestamp in UTC."},"scheduledAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post will be published, or null. ISO 8601 timestamp in UTC."},"scheduledTimeZone":{"description":"Time zone the author scheduled it in, or null.","type":["string","null"]},"scheduledBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who scheduled the publication, or null."},"held":{"type":"boolean","description":"Whether the scheduled publication is waiting for a space admin because the person who scheduled it can no longer edit the post."},"pinnedInSpace":{"type":"boolean","description":"Whether the post is pinned at the top of its space's blog."},"pinnedInOrganization":{"type":"boolean","description":"Whether the post is pinned in the organization's blog overview."},"cover":{"anyOf":[{"type":"object","properties":{"attachmentId":{"type":"string","format":"uuid","description":"The image attachment."},"focusX":{"type":"number","description":"Horizontal focal point from 0 (left) to 1 (right)."},"focusY":{"type":"number","description":"Vertical focal point from 0 (top) to 1 (bottom)."}},"required":["attachmentId","focusX","focusY"],"additionalProperties":false},{"type":"null"}],"description":"Cover image with the point that stays visible in every crop, or null."},"commentCount":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Number of comments and replies on the post that are not deleted."},"createdAt":{"type":"string","format":"date-time","description":"When the post was created. ISO 8601 timestamp in UTC."}},"required":["id","number","spaceId","spaceKey","spaceName","title","excerpt","labels","author","published","publishedAt","scheduledAt","scheduledTimeZone","scheduledBy","held","pinnedInSpace","pinnedInOrganization","cover","commentCount","createdAt"],"additionalProperties":false,"description":"A blog post."},"description":"Posts: pinned ones first, then the newest."},"nextCursor":{"description":"Cursor for the next page, or null on the last page.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"Blog posts."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5d01","number":1077,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","title":"New VPN client from Monday","excerpt":"The company portal ships WireGuard 0.6 on Monday.","labels":["vpn"],"author":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"published":true,"publishedAt":"2026-10-06T07:00:00.000Z","scheduledAt":null,"scheduledTimeZone":null,"scheduledBy":null,"held":false,"pinnedInSpace":false,"pinnedInOrganization":true,"cover":{"attachmentId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","focusX":0.5,"focusY":0.3},"commentCount":4,"createdAt":"2026-10-05T15:00:00.000Z"}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"blog.create","summary":"Write a blog post","description":"Creates a blog post as a draft. Blog posts always use publish mode: edit the content like a page, then publish it or schedule the publication.\n\nRequires the permission `space.edit` on the space in `spaceId`.","tags":["Blog"],"x-lunedo-permission":{"action":"space.edit","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","maxLength":255,"description":"Title, 1 to 255 characters."},"excerpt":{"description":"Summary, up to 500 characters.","type":"string","maxLength":500}},"required":["title"],"additionalProperties":false,"description":"A new blog post. It starts as a draft visible to editors."},"example":{"title":"New VPN client from Monday","excerpt":"The company portal ships WireGuard 0.6."}}}},"responses":{"201":{"description":"The new post.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the blog post in the addresses of the app."},"spaceId":{"type":"string","format":"uuid","description":"Space of the post."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."},"title":{"type":"string","description":"Title as readers see it."},"excerpt":{"type":"string","description":"Short summary shown in lists."},"labels":{"type":"array","items":{"type":"string","description":"A label."},"description":"Labels, sorted."},"author":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who wrote the post, or null."},"published":{"type":"boolean","description":"Whether the post was published. Unpublished posts are visible only to editors."},"publishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post was first published, or null. ISO 8601 timestamp in UTC."},"scheduledAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post will be published, or null. ISO 8601 timestamp in UTC."},"scheduledTimeZone":{"description":"Time zone the author scheduled it in, or null.","type":["string","null"]},"scheduledBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who scheduled the publication, or null."},"held":{"type":"boolean","description":"Whether the scheduled publication is waiting for a space admin because the person who scheduled it can no longer edit the post."},"pinnedInSpace":{"type":"boolean","description":"Whether the post is pinned at the top of its space's blog."},"pinnedInOrganization":{"type":"boolean","description":"Whether the post is pinned in the organization's blog overview."},"cover":{"anyOf":[{"type":"object","properties":{"attachmentId":{"type":"string","format":"uuid","description":"The image attachment."},"focusX":{"type":"number","description":"Horizontal focal point from 0 (left) to 1 (right)."},"focusY":{"type":"number","description":"Vertical focal point from 0 (top) to 1 (bottom)."}},"required":["attachmentId","focusX","focusY"],"additionalProperties":false},{"type":"null"}],"description":"Cover image with the point that stays visible in every crop, or null."},"commentCount":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Number of comments and replies on the post that are not deleted."},"createdAt":{"type":"string","format":"date-time","description":"When the post was created. ISO 8601 timestamp in UTC."}},"required":["id","number","spaceId","spaceKey","spaceName","title","excerpt","labels","author","published","publishedAt","scheduledAt","scheduledTimeZone","scheduledBy","held","pinnedInSpace","pinnedInOrganization","cover","commentCount","createdAt"],"additionalProperties":false,"description":"A blog post."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5d01","number":1077,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","title":"New VPN client from Monday","excerpt":"The company portal ships WireGuard 0.6 on Monday.","labels":["vpn"],"author":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"published":false,"publishedAt":"2026-10-06T07:00:00.000Z","scheduledAt":null,"scheduledTimeZone":null,"scheduledBy":null,"held":false,"pinnedInSpace":false,"pinnedInOrganization":true,"cover":{"attachmentId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","focusX":0.5,"focusY":0.3},"commentCount":4,"createdAt":"2026-10-05T15:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidExcerpt`: The excerpt is too long. `invalidInput`: The request is not valid. `invalidTitle`: The title is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidExcerpt":{"value":{"type":"urn:lunedo:problem:invalidExcerpt","title":"The excerpt is too long","status":400,"code":"invalidExcerpt"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidTitle":{"value":{"type":"urn:lunedo:problem:invalidTitle","title":"The title is not valid","status":400,"code":"invalidTitle"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`knowledgeBaseContent`: A knowledge base holds only articles and categories.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"knowledgeBaseContent":{"value":{"type":"urn:lunedo:problem:knowledgeBaseContent","title":"A knowledge base holds only articles and categories","status":409,"code":"knowledgeBaseContent"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/blog/scheduled":{"get":{"operationId":"blog.listScheduled","summary":"List scheduled blog posts of a space","description":"Lists every scheduled post of the space for its space admins, the held ones first, then by scheduled time.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Blog"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The scheduled posts.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the blog post in the addresses of the app."},"spaceId":{"type":"string","format":"uuid","description":"Space of the post."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."},"title":{"type":"string","description":"Title as readers see it."},"excerpt":{"type":"string","description":"Short summary shown in lists."},"labels":{"type":"array","items":{"type":"string","description":"A label."},"description":"Labels, sorted."},"author":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who wrote the post, or null."},"published":{"type":"boolean","description":"Whether the post was published. Unpublished posts are visible only to editors."},"publishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post was first published, or null. ISO 8601 timestamp in UTC."},"scheduledAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the post will be published, or null. ISO 8601 timestamp in UTC."},"scheduledTimeZone":{"description":"Time zone the author scheduled it in, or null.","type":["string","null"]},"scheduledBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who scheduled the publication, or null."},"held":{"type":"boolean","description":"Whether the scheduled publication is waiting for a space admin because the person who scheduled it can no longer edit the post."},"pinnedInSpace":{"type":"boolean","description":"Whether the post is pinned at the top of its space's blog."},"pinnedInOrganization":{"type":"boolean","description":"Whether the post is pinned in the organization's blog overview."},"cover":{"anyOf":[{"type":"object","properties":{"attachmentId":{"type":"string","format":"uuid","description":"The image attachment."},"focusX":{"type":"number","description":"Horizontal focal point from 0 (left) to 1 (right)."},"focusY":{"type":"number","description":"Vertical focal point from 0 (top) to 1 (bottom)."}},"required":["attachmentId","focusX","focusY"],"additionalProperties":false},{"type":"null"}],"description":"Cover image with the point that stays visible in every crop, or null."},"commentCount":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Number of comments and replies on the post that are not deleted."},"createdAt":{"type":"string","format":"date-time","description":"When the post was created. ISO 8601 timestamp in UTC."}},"required":["id","number","spaceId","spaceKey","spaceName","title","excerpt","labels","author","published","publishedAt","scheduledAt","scheduledTimeZone","scheduledBy","held","pinnedInSpace","pinnedInOrganization","cover","commentCount","createdAt"],"additionalProperties":false,"description":"A blog post."},"description":"Scheduled posts."}},"required":["items"],"additionalProperties":false,"description":"Scheduled posts."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5d01","number":1077,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","title":"New VPN client from Monday","excerpt":"The company portal ships WireGuard 0.6 on Monday.","labels":["vpn"],"author":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"published":false,"publishedAt":"2026-10-06T07:00:00.000Z","scheduledAt":null,"scheduledTimeZone":null,"scheduledBy":null,"held":true,"pinnedInSpace":false,"pinnedInOrganization":true,"cover":{"attachmentId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","focusX":0.5,"focusY":0.3},"commentCount":4,"createdAt":"2026-10-05T15:00:00.000Z"}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/blog/subscription":{"delete":{"operationId":"blog.unfollow","summary":"Stop following a blog","description":"Ends the subscription. It succeeds also when you did not follow the blog.\n\nRequires the permission `instance.content.view` on the instance. Needs a signed-in session; API tokens are refused.","tags":["Blog"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"get":{"operationId":"blog.subscription","summary":"Check whether you follow a blog","description":"Says whether the caller gets a notification for new posts of the space's blog.\n\nRequires the permission `space.view` on the space in `spaceId`. Needs a signed-in session; API tokens are refused.","tags":["Blog"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The subscription.","content":{"application/json":{"schema":{"type":"object","properties":{"following":{"type":"boolean","description":"Whether the caller follows the blog of the space."}},"required":["following"],"additionalProperties":false,"description":"The caller's subscription."},"example":{"following":true}}}},"400":{"description":"`invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}}}},"put":{"operationId":"blog.follow","summary":"Follow a blog","description":"You get a notification for every new post of the space's blog that you can read, when it is published. Posts you wrote yourself are left out. While you cannot read the space, the subscription stays but sends nothing.\n\nRequires the permission `space.view` on the space in `spaceId`. Needs a signed-in session; API tokens are refused.","tags":["Blog"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `sessionRequired`: This endpoint needs a signed-in session.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"sessionRequired":{"value":{"type":"urn:lunedo:problem:sessionRequired","title":"This endpoint needs a signed-in session","status":403,"code":"sessionRequired"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/categories":{"get":{"operationId":"knowledgeBases.categories","summary":"List the categories of a knowledge base","description":"Lists every folder of the knowledge base the caller can read, at any depth, top level first and then by position. Top-level folders are the areas of the portal, deeper folders its topics.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Folders the caller can read.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the category, a folder in the knowledge base."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Parent folder, or null for a top-level folder (an area of the portal)."},"level":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Depth of the folder: 1 at the top level, 2 inside it, and so on."},"title":{"type":"string","description":"Title of the folder."},"description":{"type":"string","description":"Short introduction. Supports `**bold**`, `*italic*`, links as `[text](https://…)` and one callout as lines starting with `>`."},"icon":{"description":"Name of a Lucide icon, or null.","type":["string","null"]},"contactEmail":{"anyOf":[{"type":"string","maxLength":254},{"type":"null"}],"description":"Contact address set on the category itself, or null."},"effectiveContactEmail":{"anyOf":[{"type":"string","maxLength":254},{"type":"null"}],"description":"Contact address that applies: of the folder, else of the nearest parent folder with one, else of the knowledge base."},"contactSource":{"anyOf":[{"type":"string","enum":["category","parentCategory","knowledgeBase"]},{"type":"null"}],"description":"Where the contact address that applies comes from: the folder itself, a parent folder or the knowledge base; null when none is set."},"position":{"type":"string","description":"Sort key among the siblings. Categories sort by it in binary order."},"articles":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of articles in the folder and below that the caller can read: published or live, in the default language, neither archived nor in the trash."},"drafts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of articles in the folder and below that the caller can read and that were never published."}},"required":["id","parentId","level","title","description","icon","contactEmail","effectiveContactEmail","contactSource","position","articles","drafts"],"additionalProperties":false,"description":"A folder of a knowledge base, at any depth."},"description":"Folders, top level first."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","parentId":null,"level":1,"title":"IT","description":"Devices, accounts and network","icon":"monitor","contactEmail":"it@example.org","effectiveContactEmail":"it@example.org","contactSource":"category","position":"a0","articles":12,"drafts":2}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notKnowledgeBase`: The space is not a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/chat-channels":{"get":{"operationId":"chatChannels.listSpace","summary":"List the chat channels of a space","description":"Shows the channels with their state. Addresses and tokens are never returned.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Chat channels"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The channels.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the channel."},"kind":{"type":"string","description":"Service of the channel: Microsoft Teams (Workflows webhook), Slack, Matrix, Discord or a generic webhook. New values can be added in later versions; handle unknown values.","x-extensible-enum":["teams","slack","matrix","discord","webhook"]},"name":{"type":"string","description":"Name of the channel in Lunedo."},"events":{"type":"array","items":{"type":"string","description":"An event that is posted. New values can be added in later versions; handle unknown values.","x-extensible-enum":["pagePublished","pageChanged","blogPostPublished","decisionRecorded","pageStatusChanged","commentCreated","announcementPublished"]},"description":"What is posted."},"state":{"type":"string","description":"`failing` when the service stopped accepting messages; nothing is posted until the channel is fixed. New values can be added in later versions; handle unknown values.","x-extensible-enum":["working","failing"]},"failure":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Why the service did not accept messages. New values can be added in later versions; handle unknown values.","x-extensible-enum":["addressGone","unauthorized","rejected","unavailable","unreachable","blockedAddress","insecureAddress"]},"status":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"HTTP status the service answered with, if it answered."},"code":{"description":"Error code the service reported, such as `invalid_token`, if any.","type":["string","null"]},"at":{"type":"string","format":"date-time","description":"When the channel started failing or the last test failed. ISO 8601 timestamp in UTC."}},"required":["reason","status","code","at"],"additionalProperties":false},{"type":"null"}],"description":"Why the channel is failing, or, while it is `working`, why the last test failed. Null once a message was accepted again."},"lastAttemptAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When a message was last sent. ISO 8601 timestamp in UTC."},"lastDeliveredAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When a message was last accepted. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the channel was connected. ISO 8601 timestamp in UTC."}},"required":["id","kind","name","events","state","failure","lastAttemptAt","lastDeliveredAt","createdAt"],"additionalProperties":false,"description":"A chat channel. Addresses and tokens are never returned."},"description":"The channels."}},"required":["items"],"additionalProperties":false,"description":"Chat channels."},"example":{"items":[{"id":"0192a0d4-5b6e-7c3f-8a10-3e2f4c5d6e7f","kind":"teams","name":"IT-Ops · General","events":["pagePublished","blogPostPublished","decisionRecorded"],"state":"working","failure":null,"lastAttemptAt":"2026-10-15T08:12:00.000Z","lastDeliveredAt":"2026-10-15T08:12:00.000Z","createdAt":"2026-10-01T09:00:00.000Z"}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"chatChannels.createSpace","summary":"Connect a space to a chat channel","description":"Only content every member of the space can read is posted: restricted pages, their comments and drafts never are. Confidential spaces cannot have chat channels.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Chat channels"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","description":"Service of the channel: Microsoft Teams (Workflows webhook), Slack, Matrix, Discord or a generic webhook. New values can be added in later versions; handle unknown values.","x-extensible-enum":["teams","slack","matrix","discord","webhook"]},"name":{"type":"string","minLength":1,"maxLength":80,"description":"Name of the channel in Lunedo."},"events":{"minItems":1,"maxItems":7,"type":"array","items":{"type":"string","enum":["pagePublished","pageChanged","blogPostPublished","decisionRecorded","pageStatusChanged","commentCreated","announcementPublished"]},"description":"What is posted. Spaces: `pagePublished`, `pageChanged` (combined per hour), `blogPostPublished`, `decisionRecorded`, `pageStatusChanged`, `commentCreated`. Organizations: `announcementPublished`."},"target":{"anyOf":[{"type":"object","properties":{"url":{"type":"string","minLength":1,"maxLength":2000,"description":"Webhook address the service created. Stored encrypted and never returned."}},"required":["url"],"additionalProperties":false,"description":"For Teams, Slack, Discord and generic webhooks."},{"type":"object","properties":{"homeserver":{"type":"string","minLength":1,"maxLength":2000,"description":"Address of the Matrix homeserver."},"roomId":{"type":"string","minLength":1,"maxLength":500,"description":"Room as people see it in their client: an alias such as `#ops:example.org`, a matrix.to link or a room ID such as `!abc:example.org`. Aliases and links are resolved to the room ID when saving."},"accessToken":{"type":"string","minLength":1,"maxLength":2000,"description":"Access token of the bot account. Stored encrypted and never returned."}},"required":["homeserver","roomId","accessToken"],"additionalProperties":false,"description":"For Matrix."}],"description":"Where messages go. Private, loopback and link-local addresses are refused unless the instance allows them."}},"required":["kind","name","events","target"],"additionalProperties":false,"description":"The channel to connect."},"example":{"kind":"teams","name":"IT-Ops · General","events":["pagePublished","blogPostPublished","decisionRecorded"],"target":{"url":"https://prod-12.westeurope.logic.azure.com/workflows/abc/triggers/manual/paths/invoke"}}}}},"responses":{"201":{"description":"The channel.","content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the channel."},"kind":{"type":"string","description":"Service of the channel: Microsoft Teams (Workflows webhook), Slack, Matrix, Discord or a generic webhook. New values can be added in later versions; handle unknown values.","x-extensible-enum":["teams","slack","matrix","discord","webhook"]},"name":{"type":"string","description":"Name of the channel in Lunedo."},"events":{"type":"array","items":{"type":"string","description":"An event that is posted. New values can be added in later versions; handle unknown values.","x-extensible-enum":["pagePublished","pageChanged","blogPostPublished","decisionRecorded","pageStatusChanged","commentCreated","announcementPublished"]},"description":"What is posted."},"state":{"type":"string","description":"`failing` when the service stopped accepting messages; nothing is posted until the channel is fixed. New values can be added in later versions; handle unknown values.","x-extensible-enum":["working","failing"]},"failure":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Why the service did not accept messages. New values can be added in later versions; handle unknown values.","x-extensible-enum":["addressGone","unauthorized","rejected","unavailable","unreachable","blockedAddress","insecureAddress"]},"status":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"HTTP status the service answered with, if it answered."},"code":{"description":"Error code the service reported, such as `invalid_token`, if any.","type":["string","null"]},"at":{"type":"string","format":"date-time","description":"When the channel started failing or the last test failed. ISO 8601 timestamp in UTC."}},"required":["reason","status","code","at"],"additionalProperties":false},{"type":"null"}],"description":"Why the channel is failing, or, while it is `working`, why the last test failed. Null once a message was accepted again."},"lastAttemptAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When a message was last sent. ISO 8601 timestamp in UTC."},"lastDeliveredAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When a message was last accepted. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the channel was connected. ISO 8601 timestamp in UTC."}},"required":["id","kind","name","events","state","failure","lastAttemptAt","lastDeliveredAt","createdAt"],"additionalProperties":false,"description":"A chat channel. Addresses and tokens are never returned."},"signingSecret":{"description":"For generic webhooks, the secret that signs each request (header `X-Lunedo-Signature`). Shown only in this answer.","type":["string","null"]}},"required":["channel","signingSecret"],"additionalProperties":false,"description":"The saved channel."},"example":{"channel":{"id":"0192a0d4-5b6e-7c3f-8a10-3e2f4c5d6e7f","kind":"teams","name":"IT-Ops · General","events":["pagePublished","blogPostPublished","decisionRecorded"],"state":"working","failure":null,"lastAttemptAt":"2026-10-15T08:12:00.000Z","lastDeliveredAt":"2026-10-15T08:12:00.000Z","createdAt":"2026-10-01T09:00:00.000Z"},"signingSecret":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `chatAddressBlocked`: The address points to a private network. `chatAddressInsecure`: The address needs HTTPS. `invalidChatAddress`: The address of the chat service is not valid. `invalidChatChannel`: The chat channel is not valid. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"chatAddressBlocked":{"value":{"type":"urn:lunedo:problem:chatAddressBlocked","title":"The address points to a private network","status":400,"code":"chatAddressBlocked"}},"chatAddressInsecure":{"value":{"type":"urn:lunedo:problem:chatAddressInsecure","title":"The address needs HTTPS","status":400,"code":"chatAddressInsecure"}},"invalidChatAddress":{"value":{"type":"urn:lunedo:problem:invalidChatAddress","title":"The address of the chat service is not valid","status":400,"code":"invalidChatAddress"}},"invalidChatChannel":{"value":{"type":"urn:lunedo:problem:invalidChatChannel","title":"The chat channel is not valid","status":400,"code":"invalidChatChannel"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`confidentialSpace`: Confidential spaces cannot post to chat channels. `tooManyChatChannels`: There are too many chat channels.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"confidentialSpace":{"value":{"type":"urn:lunedo:problem:confidentialSpace","title":"Confidential spaces cannot post to chat channels","status":409,"code":"confidentialSpace"}},"tooManyChatChannels":{"value":{"type":"urn:lunedo:problem:tooManyChatChannels","title":"There are too many chat channels","status":409,"code":"tooManyChatChannels"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/chat-channels/{channelId}":{"delete":{"operationId":"chatChannels.removeSpace","summary":"Disconnect a chat channel from a space","description":"Deletes the stored address; messages not yet sent are dropped.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Chat channels"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"channelId","in":"path","required":true,"description":"ID of the chat channel.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"patch":{"operationId":"chatChannels.updateSpace","summary":"Change a chat channel of a space","description":"A new address or secret also clears the failing state.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Chat channels"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"channelId","in":"path","required":true,"description":"ID of the chat channel.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80,"description":"Name of the channel in Lunedo."},"events":{"minItems":1,"maxItems":7,"type":"array","items":{"type":"string","enum":["pagePublished","pageChanged","blogPostPublished","decisionRecorded","pageStatusChanged","commentCreated","announcementPublished"]},"description":"What is posted. Spaces: `pagePublished`, `pageChanged` (combined per hour), `blogPostPublished`, `decisionRecorded`, `pageStatusChanged`, `commentCreated`. Organizations: `announcementPublished`."},"target":{"description":"New address or token. Leave it out to keep the stored one.","anyOf":[{"type":"object","properties":{"url":{"type":"string","minLength":1,"maxLength":2000,"description":"Webhook address the service created. Stored encrypted and never returned."}},"required":["url"],"additionalProperties":false,"description":"For Teams, Slack, Discord and generic webhooks."},{"type":"object","properties":{"homeserver":{"type":"string","minLength":1,"maxLength":2000,"description":"Address of the Matrix homeserver."},"roomId":{"type":"string","minLength":1,"maxLength":500,"description":"Room as people see it in their client: an alias such as `#ops:example.org`, a matrix.to link or a room ID such as `!abc:example.org`. Aliases and links are resolved to the room ID when saving."},"accessToken":{"type":"string","minLength":1,"maxLength":2000,"description":"Access token of the bot account. Stored encrypted and never returned."}},"required":["homeserver","roomId","accessToken"],"additionalProperties":false,"description":"For Matrix."}]},"newSecret":{"description":"For generic webhooks: create a new signing secret, returned once in the answer.","type":"boolean"}},"additionalProperties":false,"description":"Changes to the channel."},"example":{"events":["pagePublished","pageStatusChanged"]}}}},"responses":{"200":{"description":"The channel.","content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the channel."},"kind":{"type":"string","description":"Service of the channel: Microsoft Teams (Workflows webhook), Slack, Matrix, Discord or a generic webhook. New values can be added in later versions; handle unknown values.","x-extensible-enum":["teams","slack","matrix","discord","webhook"]},"name":{"type":"string","description":"Name of the channel in Lunedo."},"events":{"type":"array","items":{"type":"string","description":"An event that is posted. New values can be added in later versions; handle unknown values.","x-extensible-enum":["pagePublished","pageChanged","blogPostPublished","decisionRecorded","pageStatusChanged","commentCreated","announcementPublished"]},"description":"What is posted."},"state":{"type":"string","description":"`failing` when the service stopped accepting messages; nothing is posted until the channel is fixed. New values can be added in later versions; handle unknown values.","x-extensible-enum":["working","failing"]},"failure":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Why the service did not accept messages. New values can be added in later versions; handle unknown values.","x-extensible-enum":["addressGone","unauthorized","rejected","unavailable","unreachable","blockedAddress","insecureAddress"]},"status":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"HTTP status the service answered with, if it answered."},"code":{"description":"Error code the service reported, such as `invalid_token`, if any.","type":["string","null"]},"at":{"type":"string","format":"date-time","description":"When the channel started failing or the last test failed. ISO 8601 timestamp in UTC."}},"required":["reason","status","code","at"],"additionalProperties":false},{"type":"null"}],"description":"Why the channel is failing, or, while it is `working`, why the last test failed. Null once a message was accepted again."},"lastAttemptAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When a message was last sent. ISO 8601 timestamp in UTC."},"lastDeliveredAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When a message was last accepted. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the channel was connected. ISO 8601 timestamp in UTC."}},"required":["id","kind","name","events","state","failure","lastAttemptAt","lastDeliveredAt","createdAt"],"additionalProperties":false,"description":"A chat channel. Addresses and tokens are never returned."},"signingSecret":{"description":"For generic webhooks, the secret that signs each request (header `X-Lunedo-Signature`). Shown only in this answer.","type":["string","null"]}},"required":["channel","signingSecret"],"additionalProperties":false,"description":"The saved channel."},"example":{"channel":{"id":"0192a0d4-5b6e-7c3f-8a10-3e2f4c5d6e7f","kind":"teams","name":"IT-Ops · General","events":["pagePublished","blogPostPublished","decisionRecorded"],"state":"working","failure":null,"lastAttemptAt":"2026-10-15T08:12:00.000Z","lastDeliveredAt":"2026-10-15T08:12:00.000Z","createdAt":"2026-10-01T09:00:00.000Z"},"signingSecret":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `chatAddressBlocked`: The address points to a private network. `chatAddressInsecure`: The address needs HTTPS. `invalidChatAddress`: The address of the chat service is not valid. `invalidChatChannel`: The chat channel is not valid. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"chatAddressBlocked":{"value":{"type":"urn:lunedo:problem:chatAddressBlocked","title":"The address points to a private network","status":400,"code":"chatAddressBlocked"}},"chatAddressInsecure":{"value":{"type":"urn:lunedo:problem:chatAddressInsecure","title":"The address needs HTTPS","status":400,"code":"chatAddressInsecure"}},"invalidChatAddress":{"value":{"type":"urn:lunedo:problem:invalidChatAddress","title":"The address of the chat service is not valid","status":400,"code":"invalidChatAddress"}},"invalidChatChannel":{"value":{"type":"urn:lunedo:problem:invalidChatChannel","title":"The chat channel is not valid","status":400,"code":"invalidChatChannel"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`confidentialSpace`: Confidential spaces cannot post to chat channels. `tooManyChatChannels`: There are too many chat channels.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"confidentialSpace":{"value":{"type":"urn:lunedo:problem:confidentialSpace","title":"Confidential spaces cannot post to chat channels","status":409,"code":"confidentialSpace"}},"tooManyChatChannels":{"value":{"type":"urn:lunedo:problem:tooManyChatChannels","title":"There are too many chat channels","status":409,"code":"tooManyChatChannels"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/chat-channels/{channelId}/test":{"post":{"operationId":"chatChannels.testSavedSpace","summary":"Send a test message to a chat channel","description":"When the service accepts it, a failing channel works again.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Chat channels"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"channelId","in":"path","required":true,"description":"ID of the chat channel.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Whether the service accepted it.","content":{"application/json":{"schema":{"type":"object","properties":{"delivered":{"type":"boolean","description":"Whether the service accepted the test message."},"failure":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Why the service did not accept messages. New values can be added in later versions; handle unknown values.","x-extensible-enum":["addressGone","unauthorized","rejected","unavailable","unreachable","blockedAddress","insecureAddress"]},"status":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"HTTP status the service answered with, if it answered."},"code":{"description":"Error code the service reported, such as `invalid_token`, if any.","type":["string","null"]}},"required":["reason","status","code"],"additionalProperties":false,"description":"Why a message was not delivered."},{"type":"null"}],"description":"Why it was not accepted, or null."}},"required":["delivered","failure"],"additionalProperties":false,"description":"Result of the test message."},"example":{"delivered":false,"failure":{"reason":"addressGone","status":404,"code":"no_service"}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`confidentialSpace`: Confidential spaces cannot post to chat channels.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"confidentialSpace":{"value":{"type":"urn:lunedo:problem:confidentialSpace","title":"Confidential spaces cannot post to chat channels","status":409,"code":"confidentialSpace"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/chat-channels/test":{"post":{"operationId":"chatChannels.testSpace","summary":"Send a test message before connecting a channel","description":"Sends one message to the address without saving it.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Chat channels"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","description":"Service of the channel: Microsoft Teams (Workflows webhook), Slack, Matrix, Discord or a generic webhook. New values can be added in later versions; handle unknown values.","x-extensible-enum":["teams","slack","matrix","discord","webhook"]},"name":{"type":"string","minLength":1,"maxLength":80,"description":"Name of the channel in Lunedo."},"events":{"minItems":1,"maxItems":7,"type":"array","items":{"type":"string","enum":["pagePublished","pageChanged","blogPostPublished","decisionRecorded","pageStatusChanged","commentCreated","announcementPublished"]},"description":"What is posted. Spaces: `pagePublished`, `pageChanged` (combined per hour), `blogPostPublished`, `decisionRecorded`, `pageStatusChanged`, `commentCreated`. Organizations: `announcementPublished`."},"target":{"anyOf":[{"type":"object","properties":{"url":{"type":"string","minLength":1,"maxLength":2000,"description":"Webhook address the service created. Stored encrypted and never returned."}},"required":["url"],"additionalProperties":false,"description":"For Teams, Slack, Discord and generic webhooks."},{"type":"object","properties":{"homeserver":{"type":"string","minLength":1,"maxLength":2000,"description":"Address of the Matrix homeserver."},"roomId":{"type":"string","minLength":1,"maxLength":500,"description":"Room as people see it in their client: an alias such as `#ops:example.org`, a matrix.to link or a room ID such as `!abc:example.org`. Aliases and links are resolved to the room ID when saving."},"accessToken":{"type":"string","minLength":1,"maxLength":2000,"description":"Access token of the bot account. Stored encrypted and never returned."}},"required":["homeserver","roomId","accessToken"],"additionalProperties":false,"description":"For Matrix."}],"description":"Where messages go. Private, loopback and link-local addresses are refused unless the instance allows them."}},"required":["kind","name","events","target"],"additionalProperties":false,"description":"The channel to connect."},"example":{"kind":"teams","name":"IT-Ops · General","events":["pagePublished","blogPostPublished","decisionRecorded"],"target":{"url":"https://prod-12.westeurope.logic.azure.com/workflows/abc/triggers/manual/paths/invoke"}}}}},"responses":{"200":{"description":"Whether the service accepted it.","content":{"application/json":{"schema":{"type":"object","properties":{"delivered":{"type":"boolean","description":"Whether the service accepted the test message."},"failure":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","description":"Why the service did not accept messages. New values can be added in later versions; handle unknown values.","x-extensible-enum":["addressGone","unauthorized","rejected","unavailable","unreachable","blockedAddress","insecureAddress"]},"status":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"HTTP status the service answered with, if it answered."},"code":{"description":"Error code the service reported, such as `invalid_token`, if any.","type":["string","null"]}},"required":["reason","status","code"],"additionalProperties":false,"description":"Why a message was not delivered."},{"type":"null"}],"description":"Why it was not accepted, or null."}},"required":["delivered","failure"],"additionalProperties":false,"description":"Result of the test message."},"example":{"delivered":false,"failure":{"reason":"addressGone","status":404,"code":"no_service"}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `chatAddressBlocked`: The address points to a private network. `chatAddressInsecure`: The address needs HTTPS. `invalidChatAddress`: The address of the chat service is not valid. `invalidChatChannel`: The chat channel is not valid. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"chatAddressBlocked":{"value":{"type":"urn:lunedo:problem:chatAddressBlocked","title":"The address points to a private network","status":400,"code":"chatAddressBlocked"}},"chatAddressInsecure":{"value":{"type":"urn:lunedo:problem:chatAddressInsecure","title":"The address needs HTTPS","status":400,"code":"chatAddressInsecure"}},"invalidChatAddress":{"value":{"type":"urn:lunedo:problem:invalidChatAddress","title":"The address of the chat service is not valid","status":400,"code":"invalidChatAddress"}},"invalidChatChannel":{"value":{"type":"urn:lunedo:problem:invalidChatChannel","title":"The chat channel is not valid","status":400,"code":"invalidChatChannel"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`confidentialSpace`: Confidential spaces cannot post to chat channels. `tooManyChatChannels`: There are too many chat channels.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"confidentialSpace":{"value":{"type":"urn:lunedo:problem:confidentialSpace","title":"Confidential spaces cannot post to chat channels","status":409,"code":"confidentialSpace"}},"tooManyChatChannels":{"value":{"type":"urn:lunedo:problem:tooManyChatChannels","title":"There are too many chat channels","status":409,"code":"tooManyChatChannels"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/delete":{"post":{"operationId":"trash.deleteSpace","summary":"Delete a space","description":"Deletes the space with all its content. It goes directly to the second stage of the trash. Until that period ends, the people who were its space admins at deletion can restore it, and for a space that is not confidential also organization administrators. Requires typing the name of the space.\n\nRequires the permission `space.delete` on the space in `spaceId`.","tags":["Trash"],"x-lunedo-permission":{"action":"space.delete","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"confirmation":{"type":"string","maxLength":200,"description":"The name of the space, typed exactly; for a personal space without a name, its key."}},"required":["confirmation"],"additionalProperties":false,"description":"Confirmation of the deletion."},"example":{"confirmation":"IT Operations"}}}},"responses":{"200":{"description":"The trash entry of the space.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the trash entry."},"spaceId":{"type":"string","format":"uuid","description":"Space of the entry."},"spaceKey":{"type":"string","description":"Key of the space."},"spaceName":{"type":"string","description":"Name of the space."},"kind":{"type":"string","enum":["items","space"],"description":"`items` for deleted pages, folders or links, `space` for a deleted space."},"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The deleted item, or null for a space."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the deleted item in the addresses of the app, or null for a space."},"itemKind":{"anyOf":[{"type":"string","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},{"type":"null"}],"description":"Kind of the deleted item, or null for a space. New values can be added in later versions; handle unknown values."},"title":{"type":"string","description":"Title of the deleted item, or name of the space."},"descendants":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of descendants deleted with the item."},"stage":{"anyOf":[{"type":"number","const":1},{"type":"number","const":2}],"description":"1 while the entry is in the space trash, 2 after that period or after the trash was emptied; then only organization administrators can restore it."},"deletedAt":{"type":"string","format":"date-time","description":"When it was deleted. ISO 8601 timestamp in UTC."},"deletedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when the account no longer exists.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who deleted it."},"stageTwoAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the entry reached stage 2, or null. ISO 8601 timestamp in UTC."},"removedAt":{"type":"string","format":"date-time","description":"When the entry will be deleted permanently, by the current retention settings. ISO 8601 timestamp in UTC."},"formerParentEntryId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The trash entry of the page or folder this item was below, when that one is in the same trash list; restoring with `withParents=true` restores both. Null otherwise."}},"required":["id","spaceId","spaceKey","spaceName","kind","itemId","number","itemKind","title","descendants","stage","deletedAt","deletedBy","stageTwoAt","removedAt","formerParentEntryId"],"additionalProperties":false,"description":"An entry of the trash."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","kind":"space","itemId":null,"number":1041,"itemKind":null,"title":"Old VPN (OpenVPN) setup","descendants":2,"stage":2,"deletedAt":"2026-10-02T10:00:00.000Z","deletedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Lukas Hofer"},"stageTwoAt":null,"removedAt":"2027-02-14T10:00:00.000Z","formerParentEntryId":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `confirmationMismatch`: The confirmation does not match. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"confirmationMismatch":{"value":{"type":"urn:lunedo:problem:confirmationMismatch","title":"The confirmation does not match","status":400,"code":"confirmationMismatch"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/exports":{"post":{"operationId":"exports.exportSpace","summary":"Export a space","description":"Starts an export of every page of the space you can read: by default a ZIP archive with the page tree as folders, each page as Markdown and HTML, the attachments next to their pages and an index.html that lists the tree, where links between exported pages become relative paths; with a format, one print-ready HTML file, PDF file or Word document of all pages and published blog posts. Only space administrators, and organization administrators with access to the space outside confidential spaces, can start it. It is refused when the file store would pass the usage level where large writes are blocked (90 % by default), and stops when the usage reaches the critical level (95 % by default) while it is written. The export runs in the background. When it is ready, you get a notification with the download; only you can open it. The download is deleted 24 hours after it was first downloaded completely, or after 7 days if it is never downloaded. You can run one export at a time and keep up to 5; a new export of the same space or page replaces the earlier one.\n\nRequires the permission `space.export` on the space in `spaceId`.","tags":["Exports"],"x-lunedo-permission":{"action":"space.export","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"description":"What to export and how. Without a body, the export is a ZIP with every page as Markdown and HTML.","type":"object","properties":{"format":{"default":"archive","description":"`archive` (the default) for a ZIP with every page as Markdown and HTML, `html` or `markdown` for a ZIP with one of them, `print` for one print-ready HTML file of up to 300 pages, `pdf` for one PDF file, which needs the optional render container, `docx` for one Word document. `site` for a ZIP with a static website of a public knowledge base: every published article, the start, category, search and contact pages, a search index, images and redirects for old addresses, with relative links so it works under any address.","type":"string","enum":["archive","html","markdown","print","pdf","docx","site"]},"attachments":{"default":true,"description":"Adds the attachments: next to their pages in a ZIP, as an appendix that lists them in `print`, `pdf` and `docx`. `archive` always contains them.","type":"boolean"},"comments":{"default":false,"description":"Adds the open comments after each page in `print`, `pdf` and `docx`.","type":"boolean"},"contents":{"default":true,"description":"Adds a table of contents in `print`, `pdf` and `docx`.","type":"boolean"},"paper":{"default":"a4","description":"Paper size for `print`, `pdf` and `docx`.","type":"string","enum":["a4","letter"]},"orientation":{"default":"portrait","description":"Orientation for `print`, `pdf` and `docx`.","type":"string","enum":["portrait","landscape"]},"siteUrl":{"default":null,"description":"For `site`: the address the website will be served from, such as `https://help.example.org/`. With it, the website gets `sitemap.xml`, `robots.txt` and language links for search engines; without it, they are left out.","anyOf":[{"type":"string","maxLength":500,"format":"uri"},{"type":"null"}]}},"additionalProperties":false},"example":{"format":"pdf","attachments":true,"comments":false,"contents":true,"paper":"a4","orientation":"portrait"}}}},"responses":{"202":{"description":"The started export.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the export."},"scope":{"type":"string","enum":["space","pages"],"description":"What is exported: `space` for a whole space, `pages` for a page with its subpages."},"format":{"type":"string","enum":["archive","html","markdown","print","pdf","docx","site"],"description":"What the file contains: `archive` a ZIP with every page as Markdown and HTML, `html` or `markdown` a ZIP with one of them, `print` one print-ready HTML file, `pdf` one PDF file, `docx` one Word document, `site` a ZIP with a static website of a public knowledge base."},"options":{"type":"object","properties":{"attachments":{"type":"boolean","description":"Whether the attachments are included or listed."},"comments":{"type":"boolean","description":"Whether open comments are included."},"contents":{"type":"boolean","description":"Whether a table of contents is included."},"paper":{"type":"string","enum":["a4","letter"],"description":"Paper size of `print`, `pdf` and `docx`."},"orientation":{"type":"string","enum":["portrait","landscape"],"description":"Orientation of `print`, `pdf` and `docx`."},"siteUrl":{"description":"Address the static website of `site` is served from, or null when none was given.","type":["string","null"]}},"required":["attachments","comments","contents","paper","orientation","siteUrl"],"additionalProperties":false,"description":"The options the export was started with."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The exported space, or null when it was deleted since."},"rootItemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The exported page for `pages`, or null."},"name":{"type":"string","description":"Name of the space or title of the page when the export was started."},"state":{"type":"string","enum":["queued","running","ready","failed"],"description":"`queued` waits for a worker, `running` is being built, `ready` can be downloaded, `failed` stopped with an error."},"progress":{"type":"object","properties":{"done":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Files written so far."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Files in the export, 0 until known."}},"required":["done","total"],"additionalProperties":false,"description":"Progress of a running export."},"fileName":{"description":"File name of the file once it is ready.","type":["string","null"]},"size":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Size of the file in bytes once it is ready."},"errorCode":{"anyOf":[{"type":"string","x-extensible-enum":["exportDisabled","noAccess","tokenRevoked","notEnoughStorage","renderUnavailable","renderFailed","renderTooLarge","tooManyPagesForFile","tooLargeToBuild","notPublic","interrupted","internalError"]},{"type":"null"}],"description":"Why a failed export stopped: export was turned off for the space, the permission to export the space or page was lost, the API token that started it was revoked, the file store ran short of free space while it was written, the render container for PDF is not set up or cannot be reached, it could not create the PDF, the document was larger than the render container accepts, the Word or PDF file would have more pages than the limit, building the file ran out of memory, the knowledge base of a static website is no longer public, the worker was interrupted too often, or an unexpected error. New values can be added in later versions; handle unknown values."},"createdAt":{"type":"string","format":"date-time","description":"When the export was started. ISO 8601 timestamp in UTC."},"finishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the export finished or failed. ISO 8601 timestamp in UTC."},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the download is deleted: 24 hours after its first complete download, at the latest 7 days after it is ready. ISO 8601 timestamp in UTC."}},"required":["id","scope","format","options","spaceId","rootItemId","name","state","progress","fileName","size","errorCode","createdAt","finishedAt","expiresAt"],"additionalProperties":false,"description":"An export of a space or of a page with its subpages, built in the background."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a90","scope":"space","format":"archive","options":{"attachments":true,"comments":false,"contents":true,"paper":"a4","orientation":"portrait","siteUrl":null},"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","rootItemId":null,"name":"IT Operations","state":"queued","progress":{"done":0,"total":0},"fileName":"IT Operations 2026-10-14.zip","size":18432112,"errorCode":null,"createdAt":"2026-10-14T09:00:00.000Z","finishedAt":"2026-10-14T09:01:12.000Z","expiresAt":"2026-10-21T09:01:12.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `exportDisabled`: Export is turned off for this space. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"exportDisabled":{"value":{"type":"urn:lunedo:problem:exportDisabled","title":"Export is turned off for this space","status":403,"code":"exportDisabled"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`exportRunning`: Another export of yours is still running. `notKnowledgeBase`: The space is not a knowledge base. `nothingToExport`: There is nothing to export. `staticSiteNotPublic`: Only public knowledge bases become a static website. `tooManyExports`: You keep as many exports as allowed. `tooManyPagesForFile`: Too many pages for a Word or PDF file. `tooManyPagesToPrint`: Too many pages to print in a browser.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"exportRunning":{"value":{"type":"urn:lunedo:problem:exportRunning","title":"Another export of yours is still running","status":409,"code":"exportRunning"}},"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}},"nothingToExport":{"value":{"type":"urn:lunedo:problem:nothingToExport","title":"There is nothing to export","status":409,"code":"nothingToExport"}},"staticSiteNotPublic":{"value":{"type":"urn:lunedo:problem:staticSiteNotPublic","title":"Only public knowledge bases become a static website","status":409,"code":"staticSiteNotPublic"}},"tooManyExports":{"value":{"type":"urn:lunedo:problem:tooManyExports","title":"You keep as many exports as allowed","status":409,"code":"tooManyExports"}},"tooManyPagesForFile":{"value":{"type":"urn:lunedo:problem:tooManyPagesForFile","title":"Too many pages for a Word or PDF file","status":409,"code":"tooManyPagesForFile"}},"tooManyPagesToPrint":{"value":{"type":"urn:lunedo:problem:tooManyPagesToPrint","title":"Too many pages to print in a browser","status":409,"code":"tooManyPagesToPrint"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode. `renderUnavailable`: Server-side PDF needs the render container.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}},"renderUnavailable":{"value":{"type":"urn:lunedo:problem:renderUnavailable","title":"Server-side PDF needs the render container","status":503,"code":"renderUnavailable"}}}}}},"507":{"description":"`notEnoughStorage`: Not enough storage for this export.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notEnoughStorage":{"value":{"type":"urn:lunedo:problem:notEnoughStorage","title":"Not enough storage for this export","status":507,"code":"notEnoughStorage"}}}}}}}}},"/api/v1/spaces/{spaceId}/exports/summary":{"get":{"operationId":"exports.spaceSummary","summary":"Count what an export of a space contains","description":"Counts the pages and published blog posts of the space that you can read, so you can choose a format before you start the export. Browsers print up to `printLimit` pages at once; `serverPdf` tells whether the render container can create PDF files instead.\n\nRequires the permission `space.export` on the space in `spaceId`.","tags":["Exports"],"x-lunedo-permission":{"action":"space.export","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The counts.","content":{"application/json":{"schema":{"type":"object","properties":{"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages you can read in the scope."},"blogPosts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Published blog posts you can read; only for a whole space."},"printLimit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Most pages a browser prints at once through the print view."},"fileLimit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Most pages a Word or PDF file can hold; larger exports need an HTML or Markdown archive."},"serverPdf":{"type":"boolean","description":"Whether the render container is set up, so PDF can be created on the server."},"largeWritesPaused":{"type":"boolean","description":"Whether the file store is so full that exports of a space or of a page with its subpages are refused right now."}},"required":["pages","blogPosts","printLimit","fileLimit","serverPdf","largeWritesPaused"],"additionalProperties":false,"description":"What an export of a space or of a page with its subpages contains."},"example":{"pages":412,"blogPosts":31,"printLimit":300,"fileLimit":1000,"serverPdf":false,"largeWritesPaused":false}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`exportDisabled`: Export is turned off for this space. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"exportDisabled":{"value":{"type":"urn:lunedo:problem:exportDisabled","title":"Export is turned off for this space","status":403,"code":"exportDisabled"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/give-access/draft":{"delete":{"operationId":"pageAccess.discardGiveAccessDraft","summary":"Discard your Give access draft","description":"Removes your unfinished Give access assistant in this space. It does nothing when there is none.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Page access"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"get":{"operationId":"pageAccess.giveAccessDraft","summary":"Read your Give access draft","description":"Returns the Give access assistant you left unfinished in this space, so it can be continued. Each person has their own draft per space.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Page access"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The draft.","content":{"application/json":{"schema":{"type":"object","properties":{"draft":{"anyOf":[{"type":"object","properties":{"step":{"type":"integer","minimum":0,"maximum":3,"description":"The step the assistant was left on, from 0 to 3."},"holder":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","enum":["account","group"],"description":"Whether a person or a group gets access."},"id":{"type":"string","format":"uuid","description":"ID of the account or group."},"name":{"type":"string","minLength":1,"maxLength":300,"description":"Name shown in the assistant."}},"required":["kind","id","name"],"additionalProperties":false},{"type":"null"}],"description":"The person or group chosen in the first step, or null."},"level":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"What they may do."},"where":{"type":"string","enum":["space","page","pageAndChildren"],"description":"Where they get access."},"page":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the page."},"title":{"type":"string","maxLength":500,"description":"Title shown in the assistant."}},"required":["id","title"],"additionalProperties":false},{"type":"null"}],"description":"The page chosen for page access, or null."}},"required":["step","holder","level","where","page"],"additionalProperties":false,"description":"An unfinished Give access assistant."},{"type":"null"}],"description":"The unfinished assistant, or null."}},"required":["draft"],"additionalProperties":false,"description":"Your unfinished Give access assistant for this space."},"example":{"draft":{"step":1,"holder":{"kind":"account","id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"level":"editor","where":"space","page":null}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"put":{"operationId":"pageAccess.saveGiveAccessDraft","summary":"Save your Give access draft","description":"Stores the state of the unfinished Give access assistant for you in this space, replacing the previous draft. Nothing changes who has access.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Page access"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"step":{"type":"integer","minimum":0,"maximum":3,"description":"The step the assistant was left on, from 0 to 3."},"holder":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","enum":["account","group"],"description":"Whether a person or a group gets access."},"id":{"type":"string","format":"uuid","description":"ID of the account or group."},"name":{"type":"string","minLength":1,"maxLength":300,"description":"Name shown in the assistant."}},"required":["kind","id","name"]},{"type":"null"}],"description":"The person or group chosen in the first step, or null."},"level":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"What they may do."},"where":{"type":"string","enum":["space","page","pageAndChildren"],"description":"Where they get access."},"page":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the page."},"title":{"type":"string","maxLength":500,"description":"Title shown in the assistant."}},"required":["id","title"]},{"type":"null"}],"description":"The page chosen for page access, or null."}},"required":["step","holder","level","where","page"],"additionalProperties":false,"description":"An unfinished Give access assistant."},"example":{"step":1,"holder":{"kind":"account","id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"level":"editor","where":"space","page":null}}}},"responses":{"200":{"description":"The draft.","content":{"application/json":{"schema":{"type":"object","properties":{"draft":{"anyOf":[{"type":"object","properties":{"step":{"type":"integer","minimum":0,"maximum":3,"description":"The step the assistant was left on, from 0 to 3."},"holder":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","enum":["account","group"],"description":"Whether a person or a group gets access."},"id":{"type":"string","format":"uuid","description":"ID of the account or group."},"name":{"type":"string","minLength":1,"maxLength":300,"description":"Name shown in the assistant."}},"required":["kind","id","name"],"additionalProperties":false},{"type":"null"}],"description":"The person or group chosen in the first step, or null."},"level":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"What they may do."},"where":{"type":"string","enum":["space","page","pageAndChildren"],"description":"Where they get access."},"page":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the page."},"title":{"type":"string","maxLength":500,"description":"Title shown in the assistant."}},"required":["id","title"],"additionalProperties":false},{"type":"null"}],"description":"The page chosen for page access, or null."}},"required":["step","holder","level","where","page"],"additionalProperties":false,"description":"An unfinished Give access assistant."},{"type":"null"}],"description":"The unfinished assistant, or null."}},"required":["draft"],"additionalProperties":false,"description":"Your unfinished Give access assistant for this space."},"example":{"draft":{"step":1,"holder":{"kind":"account","id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"level":"editor","where":"space","page":null}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/give-access/preview":{"post":{"operationId":"pageAccess.giveSpacePreview","summary":"Preview giving access to a space","description":"Shows how many pages the person or group could then read and edit, how many restricted pages they would still not see, and who gains access. Nothing is changed.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Page access"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"holderKind":{"type":"string","enum":["account","group"],"description":"`account` for a person, `group` for a group."},"holderId":{"type":"string","format":"uuid","description":"ID of the account or group."},"level":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"`reader`, `commenter`, `editor`, or `admin` to manage the space."},"scope":{"type":"string","enum":["space","page","pageAndChildren"],"description":"Where: the whole space, this page, or this page with its pages."}},"required":["holderKind","holderId","level","scope"],"additionalProperties":false,"description":"Access to give."},"example":{"holderKind":"account","holderId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","level":"editor","scope":"space"}}}},"responses":{"200":{"description":"The effect.","content":{"application/json":{"schema":{"type":"object","properties":{"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages in the chosen place."},"readable":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages the holder could then read."},"editable":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages the holder could then edit."},"restricted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Restricted pages the holder would still not see."},"alreadyHas":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"]},{"type":"null"}],"description":"Role the person already has in the space."},"impact":{"anyOf":[{"type":"object","properties":{"gaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who get access."},"losing":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who lose access."},"raised":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role rises."},"lowered":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role drops."},"unlisted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of affected people the caller may not see; they are counted but not listed."},"truncated":{"type":"boolean","description":"Whether `changes` lists only the first 100 people."},"changes":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."},"before":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role before the change, or null for no access."},"after":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role after the change, or null for no access."}},"required":["accountId","name","before","after"],"additionalProperties":false,"description":"How the access of one person changes."},"description":"People whose access changes, ordered by name."}},"required":["gaining","losing","raised","lowered","unlisted","truncated","changes"],"additionalProperties":false,"description":"Who gains, loses or changes access."},{"type":"object","properties":{"read":{"type":"object","properties":{"gaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who get access."},"losing":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who lose access."},"raised":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role rises."},"lowered":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role drops."},"unlisted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of affected people the caller may not see; they are counted but not listed."},"truncated":{"type":"boolean","description":"Whether `changes` lists only the first 100 people."},"changes":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."},"before":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role before the change, or null for no access."},"after":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role after the change, or null for no access."}},"required":["accountId","name","before","after"],"additionalProperties":false,"description":"How the access of one person changes."},"description":"People whose access changes, ordered by name."}},"required":["gaining","losing","raised","lowered","unlisted","truncated","changes"],"additionalProperties":false,"description":"Who gains or loses the right to read."},"edit":{"type":"object","properties":{"gaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who get access."},"losing":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who lose access."},"raised":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role rises."},"lowered":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role drops."},"unlisted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of affected people the caller may not see; they are counted but not listed."},"truncated":{"type":"boolean","description":"Whether `changes` lists only the first 100 people."},"changes":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."},"before":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role before the change, or null for no access."},"after":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role after the change, or null for no access."}},"required":["accountId","name","before","after"],"additionalProperties":false,"description":"How the access of one person changes."},"description":"People whose access changes, ordered by name."}},"required":["gaining","losing","raised","lowered","unlisted","truncated","changes"],"additionalProperties":false,"description":"Who gains or loses the right to edit."}},"required":["read","edit"],"additionalProperties":false,"description":"How access to the page would change."}],"description":"Who gains or loses access: for the space, or for read and edit of the page."}},"required":["pages","readable","editable","restricted","alreadyHas","impact"],"additionalProperties":false,"description":"The effect of giving access."},"example":{"pages":34,"readable":31,"editable":31,"restricted":3,"alreadyHas":null,"impact":{"gaining":1,"losing":0,"raised":0,"lowered":0,"unlisted":0,"truncated":false,"changes":[{"accountId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger","before":null,"after":"reader"}]}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/items":{"get":{"operationId":"items.children","summary":"List items of the page tree","description":"Lists the root items of a space or the children of an item, in tree order. Children load per level, so large spaces stay fast. The response carries an `ETag`; a request with the same value in `If-None-Match` answers `304` without a body while the list is unchanged.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Pages"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"parentId","in":"query","required":false,"description":"Parent item. Leave it out for the root of the tree.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Cursor from `nextCursor` of the previous page.","schema":{"type":"string","maxLength":20000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items, from 1 to 500. Default 200.","schema":{"default":200,"type":"integer","minimum":1,"maximum":500}}],"responses":{"200":{"description":"The items.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the item."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app, unique in the instance. It never changes and is never reused."},"spaceId":{"type":"string","format":"uuid","description":"Space of the item."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Parent item, or null at the root of the tree."},"kind":{"type":"string","description":"`page`, `folder`, `link`, `blogPost`, `meetingSeries`, `meetingTopic` or `whiteboard`. Blog posts and topics are not part of the tree; they appear in the blog and the meetings of their space. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title. Empty for a link to content the caller cannot read."},"description":{"type":"string","description":"Short description of a folder."},"width":{"type":"string","enum":["fixed","full"],"description":"Page width: `fixed` or `full`."},"numberHeadings":{"type":"boolean","description":"Whether the headings of the page are numbered in the page, in print and in Word."},"mode":{"type":"string","enum":["publish","live"],"description":"Editing mode of a page: `publish` (readers see the last published version while editors work on a draft) or `live` (readers see every change at once). Folders and links are always `live`."},"published":{"type":"boolean","description":"Whether readers can see the page. False for a page in publish mode that was never published; only editors see it."},"archived":{"type":"boolean","description":"Whether the item is archived. Archived items are read-only."},"position":{"type":"string","description":"Sort key among the siblings. Items sort by it in binary order."},"hasChildren":{"type":"boolean","description":"Whether the item has children."},"viewRestriction":{"type":"string","enum":["none","own","inherited"],"description":"Whether only an access list may view the item: set on the item itself, on a page above, or not at all."},"editRestricted":{"type":"boolean","description":"Whether only an access list may edit the item."},"link":{"anyOf":[{"type":"object","properties":{"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Linked page, folder or whiteboard, or null for an address or when the caller cannot read it."},"url":{"description":"Linked `http` or `https` address, or null.","type":["string","null"]},"accessible":{"type":"boolean","description":"Whether the caller can open the target. If not, the title is empty."},"inTrash":{"type":"boolean","description":"Whether the target is in the trash. Only true for callers who could read it before."},"target":{"anyOf":[{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"Space of the target."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the target in the addresses of the app."},"spaceKey":{"type":"string","description":"Key of that space."},"kind":{"type":"string","description":"Kind of the target. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title of the target."}},"required":["spaceId","number","spaceKey","kind","title"],"additionalProperties":false},{"type":"null"}],"description":"The linked page, folder or whiteboard, or null."}},"required":["itemId","url","accessible","inTrash","target"],"additionalProperties":false,"description":"Where a link in the page tree points."},{"type":"null"}],"description":"Target of a link, or null for pages and folders."},"creatorId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Account that created the item, or null."},"contentLanguage":{"anyOf":[{"type":"string","description":"Content language as an ISO 639-1 code, or `other` for a language without its own word matching. Words are then matched as written. New values can be added in later versions; handle unknown values.","x-extensible-enum":["ar","ca","da","de","el","en","es","eu","fi","fr","ga","hi","hu","hy","id","it","lt","nb","ne","nl","pt","ro","ru","sr","sv","ta","tr","yi","other"]},{"type":"null"}],"description":"Language of the page content for search, or null to use the language of the space."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Type of an article in a knowledge base, or null for other items and articles without a type."},"translationOf":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Original article of a translation in a knowledge base, or null. A translation is listed below its original; `contentLanguage` is its language."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of the item, or null. The owner stays set when the person leaves; `owner.active` in the item details says whether the item has an active owner."},"status":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the status value."},"builtIn":{"anyOf":[{"type":"string","x-extensible-enum":["roughDraft","inProgress","readyForReview","verified"]},{"type":"null"}],"description":"Which default value this is, or null for a value a space admin added. Clients show the translated name of a default value unless `name` is set. New values can be added in later versions; handle unknown values."},"name":{"description":"Name set by a space admin, or null to show the default name.","type":["string","null"]},"color":{"type":"string","enum":["neutral","accent","info","success","warning","danger"],"description":"Color of the status: `neutral`, `accent`, `info`, `success`, `warning` or `danger`."}},"required":["id","builtIn","name","color"],"additionalProperties":false,"description":"A page status."},{"type":"null"}],"description":"Status of a page, or null when it has none or page status is turned off in the space."},"createdAt":{"type":"string","format":"date-time","description":"When the item was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the item last changed in the tree. ISO 8601 timestamp in UTC."},"contentUpdatedAt":{"type":"string","format":"date-time","description":"When the content of the page last changed. ISO 8601 timestamp in UTC."},"updatedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when the caller may not see it.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who made the change readers see last: the publisher of the current version, or the last editor of a live page or whiteboard. Null for folders and links, or when unknown."}},"required":["id","number","spaceId","parentId","kind","title","description","width","numberHeadings","mode","published","archived","position","hasChildren","viewRestriction","editRestricted","link","creatorId","contentLanguage","articleType","translationOf","ownerId","status","createdAt","updatedAt","contentUpdatedAt","updatedBy"],"additionalProperties":false,"description":"A child item."},"description":"Children, in tree order."},"nextCursor":{"description":"Cursor for the next page, or null on the last page.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"Children of an item or the root items of a space."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","parentId":null,"kind":"page","title":"VPN access for remote staff","description":"","width":"fixed","numberHeadings":false,"mode":"publish","published":true,"archived":false,"position":"a1","hasChildren":false,"viewRestriction":"none","editRestricted":false,"link":null,"creatorId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","ownerId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","contentLanguage":null,"articleType":null,"translationOf":null,"status":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","builtIn":"verified","name":null,"color":"success"},"createdAt":"2026-10-05T08:00:00.000Z","updatedAt":"2026-10-05T08:00:00.000Z","contentUpdatedAt":"2026-10-05T08:00:00.000Z","updatedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"}}],"nextCursor":null}}}},"304":{"description":"Not modified: the response matches the `If-None-Match` header."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"items.create","summary":"Create a page, folder, link or whiteboard","description":"Creates an item in the page tree, at the end of its parent unless a neighbor is given. A whiteboard starts empty. Links point to a page or folder in any space the caller can read, or to an `http` or `https` address. A page can start from a template; later changes to the template do not change the page. A new page in publish mode is visible only to editors until it is published.\n\nRequires the permission `space.edit` on the space in `spaceId`.","tags":["Pages"],"x-lunedo-permission":{"action":"space.edit","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["page","folder","link","whiteboard"],"description":"`page`, `folder`, `link` or `whiteboard`. Blog posts are created in the blog of a space, meeting series in its meetings."},"title":{"type":"string","maxLength":255,"description":"Title, 1 to 255 characters."},"description":{"description":"Short description of a folder, up to 1000 characters.","type":"string","maxLength":1000},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Parent item, or null for the root of the tree."},"beforeId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Place the item directly before this sibling."},"afterId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Place the item directly after this sibling. Without either, the item goes last."},"mode":{"description":"Editing mode of a new page. Without it, the default of the space applies. Articles of a knowledge base always use `publish`.","type":"string","enum":["publish","live"]},"articleType":{"description":"Type of a new article in a knowledge base. A template with a type sets it instead.","anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}]},"template":{"description":"Create the page from a template. The title may be left empty to use the title pattern or the template's title.","type":"object","properties":{"id":{"type":"string","maxLength":100,"description":"ID of the template, as listed by the template gallery of the space."},"values":{"default":{},"description":"Values of the template's input fields by key. Dates as `YYYY-MM-DD` (default today), people as account IDs, choices as one of the options.","type":"object","propertyNames":{"type":"string","maxLength":40},"additionalProperties":{"type":"string","maxLength":200}},"titlePattern":{"description":"Title with `{key}` for input fields, used instead of the template's title, as a template button sets it. Unknown keys become empty.","type":"string","maxLength":255}},"required":["id"],"additionalProperties":false},"link":{"description":"Target of a link. Required for links, ignored otherwise.","type":"object","properties":{"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Page, folder or whiteboard to link to, in any space the caller can read."},"url":{"description":"`http` or `https` address to link to.","anyOf":[{"type":"string","maxLength":2048},{"type":"null"}]}},"additionalProperties":false}},"required":["kind","title","parentId"],"additionalProperties":false,"description":"A new item of the page tree."},"example":{"kind":"page","title":"VPN access for remote staff","parentId":null}}}},"responses":{"201":{"description":"The new item.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the item."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app, unique in the instance. It never changes and is never reused."},"spaceId":{"type":"string","format":"uuid","description":"Space of the item."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Parent item, or null at the root of the tree."},"kind":{"type":"string","description":"`page`, `folder`, `link`, `blogPost`, `meetingSeries`, `meetingTopic` or `whiteboard`. Blog posts and topics are not part of the tree; they appear in the blog and the meetings of their space. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title. Empty for a link to content the caller cannot read."},"description":{"type":"string","description":"Short description of a folder."},"width":{"type":"string","enum":["fixed","full"],"description":"Page width: `fixed` or `full`."},"numberHeadings":{"type":"boolean","description":"Whether the headings of the page are numbered in the page, in print and in Word."},"mode":{"type":"string","enum":["publish","live"],"description":"Editing mode of a page: `publish` (readers see the last published version while editors work on a draft) or `live` (readers see every change at once). Folders and links are always `live`."},"published":{"type":"boolean","description":"Whether readers can see the page. False for a page in publish mode that was never published; only editors see it."},"archived":{"type":"boolean","description":"Whether the item is archived. Archived items are read-only."},"position":{"type":"string","description":"Sort key among the siblings. Items sort by it in binary order."},"hasChildren":{"type":"boolean","description":"Whether the item has children."},"viewRestriction":{"type":"string","enum":["none","own","inherited"],"description":"Whether only an access list may view the item: set on the item itself, on a page above, or not at all."},"editRestricted":{"type":"boolean","description":"Whether only an access list may edit the item."},"link":{"anyOf":[{"type":"object","properties":{"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Linked page, folder or whiteboard, or null for an address or when the caller cannot read it."},"url":{"description":"Linked `http` or `https` address, or null.","type":["string","null"]},"accessible":{"type":"boolean","description":"Whether the caller can open the target. If not, the title is empty."},"inTrash":{"type":"boolean","description":"Whether the target is in the trash. Only true for callers who could read it before."},"target":{"anyOf":[{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"Space of the target."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the target in the addresses of the app."},"spaceKey":{"type":"string","description":"Key of that space."},"kind":{"type":"string","description":"Kind of the target. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title of the target."}},"required":["spaceId","number","spaceKey","kind","title"],"additionalProperties":false},{"type":"null"}],"description":"The linked page, folder or whiteboard, or null."}},"required":["itemId","url","accessible","inTrash","target"],"additionalProperties":false,"description":"Where a link in the page tree points."},{"type":"null"}],"description":"Target of a link, or null for pages and folders."},"creatorId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Account that created the item, or null."},"contentLanguage":{"anyOf":[{"type":"string","description":"Content language as an ISO 639-1 code, or `other` for a language without its own word matching. Words are then matched as written. New values can be added in later versions; handle unknown values.","x-extensible-enum":["ar","ca","da","de","el","en","es","eu","fi","fr","ga","hi","hu","hy","id","it","lt","nb","ne","nl","pt","ro","ru","sr","sv","ta","tr","yi","other"]},{"type":"null"}],"description":"Language of the page content for search, or null to use the language of the space."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Type of an article in a knowledge base, or null for other items and articles without a type."},"translationOf":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Original article of a translation in a knowledge base, or null. A translation is listed below its original; `contentLanguage` is its language."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of the item, or null. The owner stays set when the person leaves; `owner.active` in the item details says whether the item has an active owner."},"status":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the status value."},"builtIn":{"anyOf":[{"type":"string","x-extensible-enum":["roughDraft","inProgress","readyForReview","verified"]},{"type":"null"}],"description":"Which default value this is, or null for a value a space admin added. Clients show the translated name of a default value unless `name` is set. New values can be added in later versions; handle unknown values."},"name":{"description":"Name set by a space admin, or null to show the default name.","type":["string","null"]},"color":{"type":"string","enum":["neutral","accent","info","success","warning","danger"],"description":"Color of the status: `neutral`, `accent`, `info`, `success`, `warning` or `danger`."}},"required":["id","builtIn","name","color"],"additionalProperties":false,"description":"A page status."},{"type":"null"}],"description":"Status of a page, or null when it has none or page status is turned off in the space."},"createdAt":{"type":"string","format":"date-time","description":"When the item was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the item last changed in the tree. ISO 8601 timestamp in UTC."},"contentUpdatedAt":{"type":"string","format":"date-time","description":"When the content of the page last changed. ISO 8601 timestamp in UTC."}},"required":["id","number","spaceId","parentId","kind","title","description","width","numberHeadings","mode","published","archived","position","hasChildren","viewRestriction","editRestricted","link","creatorId","contentLanguage","articleType","translationOf","ownerId","status","createdAt","updatedAt","contentUpdatedAt"],"additionalProperties":false,"description":"An item of the page tree."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","parentId":null,"kind":"page","title":"VPN access for remote staff","description":"","width":"fixed","numberHeadings":false,"mode":"publish","published":true,"archived":false,"position":"a1","hasChildren":false,"viewRestriction":"none","editRestricted":false,"link":null,"creatorId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","ownerId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","contentLanguage":null,"articleType":null,"translationOf":null,"status":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","builtIn":"verified","name":null,"color":"success"},"createdAt":"2026-10-05T08:00:00.000Z","updatedAt":"2026-10-05T08:00:00.000Z","contentUpdatedAt":"2026-10-05T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidArticleType`: Only articles have an article type. `invalidDescription`: The description is too long. `invalidInput`: The request is not valid. `invalidLinkTarget`: The link target is not valid. `invalidLinkUrl`: The link address is not valid. `invalidPlacement`: The place in the page tree is not valid. `invalidTemplateValues`: Some input values are missing or not valid. `invalidTitle`: The title is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidArticleType":{"value":{"type":"urn:lunedo:problem:invalidArticleType","title":"Only articles have an article type","status":400,"code":"invalidArticleType"}},"invalidDescription":{"value":{"type":"urn:lunedo:problem:invalidDescription","title":"The description is too long","status":400,"code":"invalidDescription"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidLinkTarget":{"value":{"type":"urn:lunedo:problem:invalidLinkTarget","title":"The link target is not valid","status":400,"code":"invalidLinkTarget"}},"invalidLinkUrl":{"value":{"type":"urn:lunedo:problem:invalidLinkUrl","title":"The link address is not valid","status":400,"code":"invalidLinkUrl"}},"invalidPlacement":{"value":{"type":"urn:lunedo:problem:invalidPlacement","title":"The place in the page tree is not valid","status":400,"code":"invalidPlacement"}},"invalidTemplateValues":{"value":{"type":"urn:lunedo:problem:invalidTemplateValues","title":"Some input values are missing or not valid","status":400,"code":"invalidTemplateValues"}},"invalidTitle":{"value":{"type":"urn:lunedo:problem:invalidTitle","title":"The title is not valid","status":400,"code":"invalidTitle"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `templateNotFound`: The template does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"templateNotFound":{"value":{"type":"urn:lunedo:problem:templateNotFound","title":"The template does not exist","status":404,"code":"templateNotFound"}}}}}},"409":{"description":"`knowledgeBaseContent`: A knowledge base holds only articles and categories. `knowledgeBaseMode`: Articles always use publish mode. `knowledgeBasePlacement`: Articles and categories are placed in categories.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"knowledgeBaseContent":{"value":{"type":"urn:lunedo:problem:knowledgeBaseContent","title":"A knowledge base holds only articles and categories","status":409,"code":"knowledgeBaseContent"}},"knowledgeBaseMode":{"value":{"type":"urn:lunedo:problem:knowledgeBaseMode","title":"Articles always use publish mode","status":409,"code":"knowledgeBaseMode"}},"knowledgeBasePlacement":{"value":{"type":"urn:lunedo:problem:knowledgeBasePlacement","title":"Articles and categories are placed in categories","status":409,"code":"knowledgeBasePlacement"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/key":{"put":{"operationId":"spaces.changeKey","summary":"Change the key of a space","description":"Changes the key that appears in addresses. Addresses with the old key keep leading to the space until another space takes that key. The change is audited.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","maxLength":20,"description":"New key, 2 to 10 letters or digits."}},"required":["key"],"additionalProperties":false,"description":"The new key. The old key keeps leading to the space until another space takes it."},"example":{"key":"IT"}}}},"responses":{"200":{"description":"The changed space.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space, 2 to 10 letters or digits. It appears in addresses."},"type":{"type":"string","description":"Type of the space: `standard` for pages, blog posts, meetings and whiteboards, or `knowledgeBase` for articles in categories. Chosen at creation. New values can be added in later versions; handle unknown values.","x-extensible-enum":["standard","knowledgeBase"]},"audience":{"anyOf":[{"type":"string","description":"Who may read a knowledge base: `public` (everyone, also without signing in, once the portal exists; in Lunedo all internal users), `signedIn` (all internal users of the instance), `groups` (members of the groups that hold the reader role) or `portal` (portal accounts; in Lunedo only holders of a role). Categories and articles can narrow it with view restrictions, never widen it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["public","signedIn","groups","portal"]},{"type":"null"}],"description":"Who may read the knowledge base, or null for other spaces."},"name":{"type":"string","description":"Name of the space. Empty for a personal space that has no name of its own."},"displayName":{"type":"string","description":"Name to show: the name of the space, or for a personal space without a name of its own \"Personal space of\" and the owner's name, in the owner's language."},"description":{"type":"string","description":"Short description, up to 1000 characters."},"visibility":{"type":"string","enum":["private","organization","instance"],"description":"Who can read the space besides its holders: `private` (only holders), `organization` (every member of the organization) or `instance` (every internal user of the instance)."},"discoverable":{"type":"boolean","description":"Whether members of the organization can find the space and ask for access without reading it."},"confidential":{"type":"boolean","description":"Whether the space is confidential: only its members can read it, and administrators cannot give themselves or others access. Chosen at creation."},"oneOnOne":{"type":"boolean","description":"Whether the space holds a one-on-one."},"quarantined":{"type":"boolean","description":"Whether the space holds an import that is not accepted yet. Only the importing administrator and the reviewers can read it."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization the space belongs to, or null for a personal space."},"organizationName":{"description":"Name of the organization, or null for a personal space.","type":["string","null"]},"personal":{"type":"boolean","description":"Whether this is a personal space."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of a personal space, or null."},"ownerName":{"description":"Name of the owner of a personal space, or null.","type":["string","null"]},"overviewItemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The overview page of the space, or null for a knowledge base."},"overviewItemNumber":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the overview page in the addresses of the app, or null for a knowledge base."},"archived":{"type":"boolean","description":"Whether the space is archived. Archived spaces are read-only."},"exportEnabled":{"type":"boolean","description":"Whether pages and the space can be exported. Space administrators turn export off and on; it applies to everyone. Turning it off does not prevent copying content."},"createdAt":{"type":"string","format":"date-time","description":"When the space was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the settings of the space last changed. ISO 8601 timestamp in UTC."}},"required":["id","key","type","audience","name","displayName","description","visibility","discoverable","confidential","oneOnOne","quarantined","organizationId","organizationName","personal","ownerId","ownerName","overviewItemId","overviewItemNumber","archived","exportEnabled","createdAt","updatedAt"],"additionalProperties":false,"description":"A space."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","key":"IT","type":"standard","audience":null,"name":"IT Operations","displayName":"IT Operations","description":"Runbooks and how-tos of the IT team","visibility":"organization","discoverable":false,"confidential":false,"oneOnOne":false,"quarantined":false,"organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","organizationName":"Example Inc.","personal":false,"ownerId":null,"ownerName":null,"overviewItemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a11","overviewItemNumber":1001,"archived":false,"exportEnabled":true,"createdAt":"2026-10-05T08:00:00.000Z","updatedAt":"2026-10-05T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidSpaceKey`: The space key is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidSpaceKey":{"value":{"type":"urn:lunedo:problem:invalidSpaceKey","title":"The space key is not valid","status":400,"code":"invalidSpaceKey"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`keyTaken`: The space key is taken.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"keyTaken":{"value":{"type":"urn:lunedo:problem:keyTaken","title":"The space key is taken","status":409,"code":"keyTaken"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/keys/{key}":{"get":{"operationId":"spaces.checkKey","summary":"Check a new key for a space","description":"Tells whether a key is valid and free, before changing the key of the space.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"key","in":"path","required":true,"description":"Key to check.","schema":{"type":"string","maxLength":20}}],"responses":{"200":{"description":"Whether the key can be used.","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"The key in its stored form, in capitals."},"valid":{"type":"boolean","description":"Whether the key has 2 to 10 letters or digits."},"available":{"type":"boolean","description":"Whether no other space uses the key."}},"required":["key","valid","available"],"additionalProperties":false,"description":"Whether a key can be used."},"example":{"key":"IT","valid":true,"available":true}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/knowledge-base":{"get":{"operationId":"knowledgeBases.settings","summary":"Get the settings of a knowledge base","description":"Returns who may read the knowledge base and its contact address.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The settings.","content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"ID of the knowledge base."},"audience":{"type":"string","description":"Who may read a knowledge base: `public` (everyone, also without signing in, once the portal exists; in Lunedo all internal users), `signedIn` (all internal users of the instance), `groups` (members of the groups that hold the reader role) or `portal` (portal accounts; in Lunedo only holders of a role). Categories and articles can narrow it with view restrictions, never widen it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["public","signedIn","groups","portal"]},"groups":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the group."},"name":{"type":"string","description":"Name of the group."}},"required":["id","name"],"additionalProperties":false,"description":"A group."},"description":"Groups that hold the reader role. They read the knowledge base when `audience` is `groups`."},"contactEmail":{"anyOf":[{"type":"string","maxLength":254},{"type":"null"}],"description":"Contact address of the knowledge base, used where no category sets its own, or null."}},"required":["spaceId","audience","groups","contactEmail"],"additionalProperties":false,"description":"Settings of a knowledge base."},"example":{"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","audience":"signedIn","groups":[],"contactEmail":"help@example.org"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notKnowledgeBase`: The space is not a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/knowledge-base/audience":{"put":{"operationId":"knowledgeBases.changeAudience","summary":"Change who may read a knowledge base","description":"Sets the audience. With `groups`, the listed groups get the reader role and groups that are no longer listed lose it; groups with a higher role keep it. A change that lets more people read needs `confirmWidening`. Every change is audited.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"audience":{"type":"string","description":"Who may read a knowledge base: `public` (everyone, also without signing in, once the portal exists; in Lunedo all internal users), `signedIn` (all internal users of the instance), `groups` (members of the groups that hold the reader role) or `portal` (portal accounts; in Lunedo only holders of a role). Categories and articles can narrow it with view restrictions, never widen it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["public","signedIn","groups","portal"]},"groupIds":{"default":[],"description":"Groups that may read the knowledge base when `audience` is `groups`. Ignored otherwise.","maxItems":100,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a group."}},"confirmWidening":{"default":false,"description":"Confirms a change that lets more people read the knowledge base. Without it such a change is refused.","type":"boolean"}},"required":["audience"],"additionalProperties":false,"description":"The new audience."},"example":{"audience":"signedIn","groupIds":[],"confirmWidening":true}}}},"responses":{"200":{"description":"The settings after the change.","content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"ID of the knowledge base."},"audience":{"type":"string","description":"Who may read a knowledge base: `public` (everyone, also without signing in, once the portal exists; in Lunedo all internal users), `signedIn` (all internal users of the instance), `groups` (members of the groups that hold the reader role) or `portal` (portal accounts; in Lunedo only holders of a role). Categories and articles can narrow it with view restrictions, never widen it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["public","signedIn","groups","portal"]},"groups":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the group."},"name":{"type":"string","description":"Name of the group."}},"required":["id","name"],"additionalProperties":false,"description":"A group."},"description":"Groups that hold the reader role. They read the knowledge base when `audience` is `groups`."},"contactEmail":{"anyOf":[{"type":"string","maxLength":254},{"type":"null"}],"description":"Contact address of the knowledge base, used where no category sets its own, or null."}},"required":["spaceId","audience","groups","contactEmail"],"additionalProperties":false,"description":"Settings of a knowledge base."},"example":{"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","audience":"signedIn","groups":[],"contactEmail":"help@example.org"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `audienceGroupsMissing`: Choose at least one group. `invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid. `portalAccountReaderOnly`: Portal accounts can only read. `tooManyGroups`: Too many groups.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"audienceGroupsMissing":{"value":{"type":"urn:lunedo:problem:audienceGroupsMissing","title":"Choose at least one group","status":400,"code":"audienceGroupsMissing"}},"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"portalAccountReaderOnly":{"value":{"type":"urn:lunedo:problem:portalAccountReaderOnly","title":"Portal accounts can only read","status":400,"code":"portalAccountReaderOnly"}},"tooManyGroups":{"value":{"type":"urn:lunedo:problem:tooManyGroups","title":"Too many groups","status":400,"code":"tooManyGroups"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `selfExtension`: Nobody can extend their own permissions.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"selfExtension":{"value":{"type":"urn:lunedo:problem:selfExtension","title":"Nobody can extend their own permissions","status":403,"code":"selfExtension"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`audienceWidening`: The change lets more people read the knowledge base. `notKnowledgeBase`: The space is not a knowledge base. `privateSpaceBroadGrant`: A private space gives roles to people and groups only.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"audienceWidening":{"value":{"type":"urn:lunedo:problem:audienceWidening","title":"The change lets more people read the knowledge base","status":409,"code":"audienceWidening"}},"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}},"privateSpaceBroadGrant":{"value":{"type":"urn:lunedo:problem:privateSpaceBroadGrant","title":"A private space gives roles to people and groups only","status":409,"code":"privateSpaceBroadGrant"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/knowledge-base/audience/preview":{"post":{"operationId":"knowledgeBases.previewAudience","summary":"Preview a change of the audience","description":"Says whether the change lets more people read the knowledge base and how many articles they could open. Nothing is changed.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"audience":{"type":"string","description":"Who may read a knowledge base: `public` (everyone, also without signing in, once the portal exists; in Lunedo all internal users), `signedIn` (all internal users of the instance), `groups` (members of the groups that hold the reader role) or `portal` (portal accounts; in Lunedo only holders of a role). Categories and articles can narrow it with view restrictions, never widen it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["public","signedIn","groups","portal"]},"groupIds":{"default":[],"description":"Groups that may read the knowledge base when `audience` is `groups`. Ignored otherwise.","maxItems":100,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a group."}}},"required":["audience"],"additionalProperties":false,"description":"The new audience."},"example":{"audience":"public","groupIds":[]}}}},"responses":{"200":{"description":"The impact.","content":{"application/json":{"schema":{"type":"object","properties":{"widening":{"type":"boolean","description":"Whether more people could read the knowledge base after the change."},"articles":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of articles without a view restriction that the new readers could open. 0 when nothing widens."}},"required":["widening","articles"],"additionalProperties":false,"description":"What the change of the audience means."},"example":{"widening":true,"articles":140}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notKnowledgeBase`: The space is not a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/knowledge-base/categories/{itemId}/access":{"put":{"operationId":"categoryAccess.change","summary":"Change who maintains and who reads a category","description":"Sets the responsible groups and the readers of a category; both apply to everything below it, and a subcategory can only name groups of the category above. Only space admins of the knowledge base change them. A change that lets more people read needs `confirmWidening`. Every change is audited.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}},{"name":"itemId","in":"path","required":true,"description":"ID of the category, a folder of the knowledge base.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"responsibleGroupIds":{"maxItems":50,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a group."},"description":"Groups that create, edit, publish, move and delete articles here. Empty: everyone with the editor role."},"visibleGroupIds":{"anyOf":[{"maxItems":50,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a group."}},{"type":"null"}],"description":"Groups that may read the category, or null to read it like the knowledge base."},"confirmWidening":{"default":false,"description":"Confirms a change that lets more people read the category. Without it such a change is refused.","type":"boolean"}},"required":["responsibleGroupIds","visibleGroupIds"],"additionalProperties":false,"description":"The new access settings."},"example":{"responsibleGroupIds":["01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a31"],"visibleGroupIds":null,"confirmWidening":false}}}},"responses":{"200":{"description":"The category after the change.","content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"ID of the category."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the category above, or null for a top-level category."},"title":{"type":"string","description":"Title of the category."},"readable":{"type":"boolean","description":"Whether the caller may read the category. Space admins also get categories they may not read, with title and settings only, so they can remove the restriction."},"responsibleGroups":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the group."},"name":{"type":"string","description":"Name of the group."}},"required":["id","name"],"additionalProperties":false,"description":"A group."},"description":"Groups, sorted by name."},{"type":"null"}],"description":"Groups set on this category that create, edit, publish, move and delete its articles; null when the category sets none. An empty list means its groups were deleted: only space admins write."},"inheritedResponsibleGroups":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the group."},"name":{"type":"string","description":"Name of the group."}},"required":["id","name"],"additionalProperties":false,"description":"A group."},"description":"Groups, sorted by name."},{"type":"null"}],"description":"Groups of the nearest category above that sets responsible groups, or null."},"visibleTo":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the group."},"name":{"type":"string","description":"Name of the group."}},"required":["id","name"],"additionalProperties":false,"description":"A group."},"description":"Groups, sorted by name."},{"type":"null"}],"description":"Groups that may read this category and everything below it, or null when it reads like the knowledge base."},"visibleToPeople":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of single people who may also read the restricted category, set before categories had their own dialog."},"inheritedVisibleTo":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the group."},"name":{"type":"string","description":"Name of the group."}},"required":["id","name"],"additionalProperties":false,"description":"A group."},"description":"Groups, sorted by name."},{"type":"null"}],"description":"Readers of the nearest restricted category above, or null."},"articles":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Articles in the category and below that the caller may count."},"subcategories":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Direct subcategories that the caller may count."},"mine":{"type":"boolean","description":"Whether the caller belongs to the responsible groups of the category, set here or above."},"writable":{"type":"boolean","description":"Whether the caller may change the articles of the category, as responsible person or space admin."}},"required":["itemId","parentId","title","readable","responsibleGroups","inheritedResponsibleGroups","visibleTo","visibleToPeople","inheritedVisibleTo","articles","subcategories","mine","writable"],"additionalProperties":false,"description":"Access settings of a category."},"example":{"itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","parentId":null,"title":"IT and devices","readable":true,"responsibleGroups":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a31","name":"IT"}],"inheritedResponsibleGroups":null,"visibleTo":null,"visibleToPeople":0,"inheritedVisibleTo":null,"articles":42,"subcategories":3,"mine":true,"writable":true}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `categoryGroupsMissing`: Choose at least one group that may read the category. `invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid. `tooManyGroups`: Too many groups.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"categoryGroupsMissing":{"value":{"type":"urn:lunedo:problem:categoryGroupsMissing","title":"Choose at least one group that may read the category","status":400,"code":"categoryGroupsMissing"}},"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"tooManyGroups":{"value":{"type":"urn:lunedo:problem:tooManyGroups","title":"Too many groups","status":400,"code":"tooManyGroups"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`categoryAccessForSpaceAdmins`: Only space admins of the knowledge base change the access of a category. `csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"categoryAccessForSpaceAdmins":{"value":{"type":"urn:lunedo:problem:categoryAccessForSpaceAdmins","title":"Only space admins of the knowledge base change the access of a category","status":403,"code":"categoryAccessForSpaceAdmins"}},"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`categoryVisibilityWidening`: The change lets more people read the category. `categoryWidensParent`: A subcategory can only name groups of the category above. `notKnowledgeBase`: The space is not a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"categoryVisibilityWidening":{"value":{"type":"urn:lunedo:problem:categoryVisibilityWidening","title":"The change lets more people read the category","status":409,"code":"categoryVisibilityWidening"}},"categoryWidensParent":{"value":{"type":"urn:lunedo:problem:categoryWidensParent","title":"A subcategory can only name groups of the category above","status":409,"code":"categoryWidensParent"}},"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/knowledge-base/categories/{itemId}/access/preview":{"post":{"operationId":"categoryAccess.preview","summary":"Preview a change of the access of a category","description":"Says who could no longer change articles, how many people lose or gain read access and how many articles are affected. Nothing is changed.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}},{"name":"itemId","in":"path","required":true,"description":"ID of the category, a folder of the knowledge base.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"responsibleGroupIds":{"maxItems":50,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a group."},"description":"Groups that create, edit, publish, move and delete articles here. Empty: everyone with the editor role."},"visibleGroupIds":{"anyOf":[{"maxItems":50,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a group."}},{"type":"null"}],"description":"Groups that may read the category, or null to read it like the knowledge base."}},"required":["responsibleGroupIds","visibleGroupIds"],"additionalProperties":false,"description":"The new access settings."},"example":{"responsibleGroupIds":["01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a31"],"visibleGroupIds":null}}}},"responses":{"200":{"description":"The effect.","content":{"application/json":{"schema":{"type":"object","properties":{"articles":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Articles in the category and below."},"widening":{"type":"boolean","description":"Whether more people could read the category after the change."},"losingWrite":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the person."},"name":{"type":"string","description":"Name of the person."}},"required":["accountId","name"],"additionalProperties":false,"description":"A person who can no longer change the articles."},"description":"People who can no longer change articles, as far as the caller may see them, up to 100."},"losingWriteCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who can no longer change articles."},"losingRead":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who can no longer read some of the articles."},"gainingRead":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who can read articles they could not read before."},"publicPortalLosesAccess":{"type":"boolean","description":"Whether anonymous readers of the public portal and the static site lose the category."},"unlisted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"People with changed access whom the caller may not see by name."}},"required":["articles","widening","losingWrite","losingWriteCount","losingRead","gainingRead","publicPortalLosesAccess","unlisted"],"additionalProperties":false,"description":"What the change means."},"example":{"articles":42,"widening":false,"losingWrite":[{"accountId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a21","name":"Lukas Hofer"}],"losingWriteCount":1,"losingRead":0,"gainingRead":0,"publicPortalLosesAccess":false,"unlisted":0}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `categoryGroupsMissing`: Choose at least one group that may read the category. `invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid. `tooManyGroups`: Too many groups.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"categoryGroupsMissing":{"value":{"type":"urn:lunedo:problem:categoryGroupsMissing","title":"Choose at least one group that may read the category","status":400,"code":"categoryGroupsMissing"}},"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"tooManyGroups":{"value":{"type":"urn:lunedo:problem:tooManyGroups","title":"Too many groups","status":400,"code":"tooManyGroups"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`categoryAccessForSpaceAdmins`: Only space admins of the knowledge base change the access of a category. `csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"categoryAccessForSpaceAdmins":{"value":{"type":"urn:lunedo:problem:categoryAccessForSpaceAdmins","title":"Only space admins of the knowledge base change the access of a category","status":403,"code":"categoryAccessForSpaceAdmins"}},"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`categoryWidensParent`: A subcategory can only name groups of the category above. `notKnowledgeBase`: The space is not a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"categoryWidensParent":{"value":{"type":"urn:lunedo:problem:categoryWidensParent","title":"A subcategory can only name groups of the category above","status":409,"code":"categoryWidensParent"}},"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/knowledge-base/category-access":{"get":{"operationId":"categoryAccess.list","summary":"List the access of the categories","description":"Lists the categories of a knowledge base that the caller may read, with their responsible groups and readers, ordered by depth and position. Space admins also get categories they may not read.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The categories.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"ID of the category."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the category above, or null for a top-level category."},"title":{"type":"string","description":"Title of the category."},"readable":{"type":"boolean","description":"Whether the caller may read the category. Space admins also get categories they may not read, with title and settings only, so they can remove the restriction."},"responsibleGroups":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the group."},"name":{"type":"string","description":"Name of the group."}},"required":["id","name"],"additionalProperties":false,"description":"A group."},"description":"Groups, sorted by name."},{"type":"null"}],"description":"Groups set on this category that create, edit, publish, move and delete its articles; null when the category sets none. An empty list means its groups were deleted: only space admins write."},"inheritedResponsibleGroups":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the group."},"name":{"type":"string","description":"Name of the group."}},"required":["id","name"],"additionalProperties":false,"description":"A group."},"description":"Groups, sorted by name."},{"type":"null"}],"description":"Groups of the nearest category above that sets responsible groups, or null."},"visibleTo":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the group."},"name":{"type":"string","description":"Name of the group."}},"required":["id","name"],"additionalProperties":false,"description":"A group."},"description":"Groups, sorted by name."},{"type":"null"}],"description":"Groups that may read this category and everything below it, or null when it reads like the knowledge base."},"visibleToPeople":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of single people who may also read the restricted category, set before categories had their own dialog."},"inheritedVisibleTo":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the group."},"name":{"type":"string","description":"Name of the group."}},"required":["id","name"],"additionalProperties":false,"description":"A group."},"description":"Groups, sorted by name."},{"type":"null"}],"description":"Readers of the nearest restricted category above, or null."},"articles":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Articles in the category and below that the caller may count."},"subcategories":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Direct subcategories that the caller may count."},"mine":{"type":"boolean","description":"Whether the caller belongs to the responsible groups of the category, set here or above."},"writable":{"type":"boolean","description":"Whether the caller may change the articles of the category, as responsible person or space admin."}},"required":["itemId","parentId","title","readable","responsibleGroups","inheritedResponsibleGroups","visibleTo","visibleToPeople","inheritedVisibleTo","articles","subcategories","mine","writable"],"additionalProperties":false,"description":"Access settings of a category."},"description":"Categories."},"example":[{"itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","parentId":null,"title":"IT and devices","readable":true,"responsibleGroups":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a31","name":"IT"}],"inheritedResponsibleGroups":null,"visibleTo":null,"visibleToPeople":0,"inheritedVisibleTo":null,"articles":42,"subcategories":3,"mine":true,"writable":true}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notKnowledgeBase`: The space is not a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/knowledge-base/contact":{"put":{"operationId":"knowledgeBases.setContact","summary":"Set the contact address of a knowledge base","description":"Sets the address used for articles whose categories have none. Lunedo sends nothing itself.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contactEmail":{"anyOf":[{"type":"string","maxLength":254},{"type":"null"}],"description":"E-mail address readers write to when an article did not help, or null."}},"required":["contactEmail"],"additionalProperties":false,"description":"The contact address."},"example":{"contactEmail":"help@example.org"}}}},"responses":{"200":{"description":"The settings after the change.","content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"ID of the knowledge base."},"audience":{"type":"string","description":"Who may read a knowledge base: `public` (everyone, also without signing in, once the portal exists; in Lunedo all internal users), `signedIn` (all internal users of the instance), `groups` (members of the groups that hold the reader role) or `portal` (portal accounts; in Lunedo only holders of a role). Categories and articles can narrow it with view restrictions, never widen it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["public","signedIn","groups","portal"]},"groups":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the group."},"name":{"type":"string","description":"Name of the group."}},"required":["id","name"],"additionalProperties":false,"description":"A group."},"description":"Groups that hold the reader role. They read the knowledge base when `audience` is `groups`."},"contactEmail":{"anyOf":[{"type":"string","maxLength":254},{"type":"null"}],"description":"Contact address of the knowledge base, used where no category sets its own, or null."}},"required":["spaceId","audience","groups","contactEmail"],"additionalProperties":false,"description":"Settings of a knowledge base."},"example":{"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","audience":"signedIn","groups":[],"contactEmail":"help@example.org"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidContactEmail`: The contact address is not valid. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidContactEmail":{"value":{"type":"urn:lunedo:problem:invalidContactEmail","title":"The contact address is not valid","status":400,"code":"invalidContactEmail"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notKnowledgeBase`: The space is not a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/knowledge-base/languages":{"get":{"operationId":"knowledgeBases.languages","summary":"Get the languages of a knowledge base","description":"Returns the default language, the enabled languages and how far the translations are.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The languages.","content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"ID of the knowledge base."},"defaultLanguage":{"type":"string","description":"Language of new articles and fallback for readers whose language has no translation."},"languages":{"type":"array","items":{"type":"string","description":"Language as a two-letter code such as `de` or `en`."},"description":"Enabled languages, including the default language. The portal offers a choice from two on."},"articles":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Published articles in the default language."},"progress":{"type":"array","items":{"type":"object","properties":{"language":{"type":"string","description":"Language as a two-letter code such as `de` or `en`."},"translated":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Articles with a published translation."},"outdated":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Translations whose original was published after them."},"missing":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Articles without a published translation."}},"required":["language","translated","outdated","missing"],"additionalProperties":false,"description":"State of the translations into one language."},"description":"State of the translations per enabled language other than the default."},"searchUpdate":{"anyOf":[{"type":"object","properties":{"remaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Articles whose search entry is still being updated."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Articles of the knowledge base."}},"required":["remaining","total"],"additionalProperties":false},{"type":"null"}],"description":"Progress of updating the search, for example after the default language changed, or null when search is up to date."}},"required":["spaceId","defaultLanguage","languages","articles","progress","searchUpdate"],"additionalProperties":false,"description":"Languages of a knowledge base."},"example":{"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","defaultLanguage":"de","languages":["de","en"],"articles":140,"progress":[{"language":"en","translated":12,"outdated":2,"missing":128}],"searchUpdate":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notKnowledgeBase`: The space is not a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"put":{"operationId":"knowledgeBases.setLanguages","summary":"Change the languages of a knowledge base","description":"Sets the default language and the enabled languages. Turning a language off keeps its translations but hides them from readers. A language that already has translations cannot become the default language. Audited.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"defaultLanguage":{"type":"string","description":"Language as a two-letter code such as `de` or `en`."},"languages":{"description":"Enabled languages. The default language is always enabled.","maxItems":30,"type":"array","items":{"type":"string","description":"Language as a two-letter code such as `de` or `en`."}}},"additionalProperties":false,"description":"The changed languages."},"example":{"languages":["de","en"]}}}},"responses":{"200":{"description":"The languages after the change.","content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"ID of the knowledge base."},"defaultLanguage":{"type":"string","description":"Language of new articles and fallback for readers whose language has no translation."},"languages":{"type":"array","items":{"type":"string","description":"Language as a two-letter code such as `de` or `en`."},"description":"Enabled languages, including the default language. The portal offers a choice from two on."},"articles":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Published articles in the default language."},"progress":{"type":"array","items":{"type":"object","properties":{"language":{"type":"string","description":"Language as a two-letter code such as `de` or `en`."},"translated":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Articles with a published translation."},"outdated":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Translations whose original was published after them."},"missing":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Articles without a published translation."}},"required":["language","translated","outdated","missing"],"additionalProperties":false,"description":"State of the translations into one language."},"description":"State of the translations per enabled language other than the default."},"searchUpdate":{"anyOf":[{"type":"object","properties":{"remaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Articles whose search entry is still being updated."},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Articles of the knowledge base."}},"required":["remaining","total"],"additionalProperties":false},{"type":"null"}],"description":"Progress of updating the search, for example after the default language changed, or null when search is up to date."}},"required":["spaceId","defaultLanguage","languages","articles","progress","searchUpdate"],"additionalProperties":false,"description":"Languages of a knowledge base."},"example":{"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","defaultLanguage":"de","languages":["de","en"],"articles":140,"progress":[{"language":"en","translated":12,"outdated":2,"missing":128}],"searchUpdate":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidLanguage`: The language is not supported. `tooManyLanguages`: Too many languages.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidLanguage":{"value":{"type":"urn:lunedo:problem:invalidLanguage","title":"The language is not supported","status":400,"code":"invalidLanguage"}},"tooManyLanguages":{"value":{"type":"urn:lunedo:problem:tooManyLanguages","title":"Too many languages","status":400,"code":"tooManyLanguages"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`defaultLanguageTranslated`: Articles already have translations into this language. `notKnowledgeBase`: The space is not a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"defaultLanguageTranslated":{"value":{"type":"urn:lunedo:problem:defaultLanguageTranslated","title":"Articles already have translations into this language","status":409,"code":"defaultLanguageTranslated"}},"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/knowledge-base/portal":{"get":{"operationId":"portal.portal","summary":"Get the portal of a knowledge base","description":"Returns the address and the appearance of the portal readers use.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The portal.","content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"ID of the knowledge base."},"path":{"type":"string","description":"Path under `/help/` on the instance."},"domain":{"description":"Own domain of the portal, or null.","type":["string","null"]},"url":{"type":"string","description":"Address of the portal's start page."},"brand":{"type":"object","properties":{"color":{"type":"string","enum":["petrol","blue","violet","amber","red","green","gray","custom"],"description":"A color of the fixed palette, or `custom` for own values."},"light":{"anyOf":[{"type":"string","maxLength":7,"description":"A color as a hex value such as `#0B6F78`."},{"type":"null"}],"description":"Own color for light mode, or null for a palette color."},"dark":{"anyOf":[{"type":"string","maxLength":7,"description":"A color as a hex value such as `#0B6F78`."},{"type":"null"}],"description":"Own color for dark mode, or null for a palette color."}},"required":["color","light","dark"],"additionalProperties":false,"description":"The brand color of the portal."},"colors":{"type":"object","properties":{"light":{"type":"string","description":"Light mode."},"dark":{"type":"string","description":"Dark mode."}},"required":["light","dark"],"additionalProperties":false,"description":"The brand colors the portal uses."},"welcomeHeading":{"type":"string","description":"Heading of the start page; empty for the default heading."},"welcomeText":{"type":"string","description":"Short text below the heading; may be empty."},"topBarThreshold":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Not used any more: the top bar always shows a single menu of all areas. Kept so that existing clients keep working."},"poweredBy":{"type":"boolean","description":"Whether the footer says that the portal is made with Lunedo."},"feedbackRetentionMonths":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Months after which readers' notes on articles are deleted."},"logoRef":{"description":"Reference of the uploaded logo, or null.","type":["string","null"]}},"required":["spaceId","path","domain","url","brand","colors","welcomeHeading","welcomeText","topBarThreshold","poweredBy","feedbackRetentionMonths","logoRef"],"additionalProperties":false,"description":"Address and appearance of a knowledge base portal."},"example":{"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","path":"help","domain":null,"url":"https://wiki.example.org/help/help/","brand":{"color":"petrol","light":null,"dark":null},"colors":{"light":"#0B6F78","dark":"#5DB9C2"},"welcomeHeading":"","welcomeText":"","topBarThreshold":10,"poweredBy":true,"feedbackRetentionMonths":12,"logoRef":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/knowledge-base/portal/address":{"put":{"operationId":"portal.setAddress","summary":"Change the address of a portal","description":"Sets the path under `/help/` and the own domain. Old paths keep redirecting until another knowledge base takes them. The change is recorded in the audit log.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"type":"string","maxLength":60,"description":"Lowercase letters, digits and single hyphens."},"domain":{"anyOf":[{"type":"string","maxLength":253},{"type":"null"}],"description":"A domain the instance administrators allowed for the organization, or null."}},"required":["path","domain"],"additionalProperties":false,"description":"The new address."},"example":{"path":"help","domain":"help.example.org"}}}},"responses":{"200":{"description":"The portal after the change.","content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"ID of the knowledge base."},"path":{"type":"string","description":"Path under `/help/` on the instance."},"domain":{"description":"Own domain of the portal, or null.","type":["string","null"]},"url":{"type":"string","description":"Address of the portal's start page."},"brand":{"type":"object","properties":{"color":{"type":"string","enum":["petrol","blue","violet","amber","red","green","gray","custom"],"description":"A color of the fixed palette, or `custom` for own values."},"light":{"anyOf":[{"type":"string","maxLength":7,"description":"A color as a hex value such as `#0B6F78`."},{"type":"null"}],"description":"Own color for light mode, or null for a palette color."},"dark":{"anyOf":[{"type":"string","maxLength":7,"description":"A color as a hex value such as `#0B6F78`."},{"type":"null"}],"description":"Own color for dark mode, or null for a palette color."}},"required":["color","light","dark"],"additionalProperties":false,"description":"The brand color of the portal."},"colors":{"type":"object","properties":{"light":{"type":"string","description":"Light mode."},"dark":{"type":"string","description":"Dark mode."}},"required":["light","dark"],"additionalProperties":false,"description":"The brand colors the portal uses."},"welcomeHeading":{"type":"string","description":"Heading of the start page; empty for the default heading."},"welcomeText":{"type":"string","description":"Short text below the heading; may be empty."},"topBarThreshold":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Not used any more: the top bar always shows a single menu of all areas. Kept so that existing clients keep working."},"poweredBy":{"type":"boolean","description":"Whether the footer says that the portal is made with Lunedo."},"feedbackRetentionMonths":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Months after which readers' notes on articles are deleted."},"logoRef":{"description":"Reference of the uploaded logo, or null.","type":["string","null"]}},"required":["spaceId","path","domain","url","brand","colors","welcomeHeading","welcomeText","topBarThreshold","poweredBy","feedbackRetentionMonths","logoRef"],"additionalProperties":false,"description":"Address and appearance of a knowledge base portal."},"example":{"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","path":"help","domain":null,"url":"https://wiki.example.org/help/help/","brand":{"color":"petrol","light":null,"dark":null},"colors":{"light":"#0B6F78","dark":"#5DB9C2"},"welcomeHeading":"","welcomeText":"","topBarThreshold":10,"poweredBy":true,"feedbackRetentionMonths":12,"logoRef":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidPortalDomain`: The domain is not valid. `invalidPortalPath`: The portal path is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidPortalDomain":{"value":{"type":"urn:lunedo:problem:invalidPortalDomain","title":"The domain is not valid","status":400,"code":"invalidPortalDomain"}},"invalidPortalPath":{"value":{"type":"urn:lunedo:problem:invalidPortalPath","title":"The portal path is not valid","status":400,"code":"invalidPortalPath"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`portalDomainNotAllowed`: The domain is not allowed for this organization. `portalDomainTaken`: Another knowledge base uses this domain. `portalPathTaken`: Another knowledge base uses this path.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"portalDomainNotAllowed":{"value":{"type":"urn:lunedo:problem:portalDomainNotAllowed","title":"The domain is not allowed for this organization","status":409,"code":"portalDomainNotAllowed"}},"portalDomainTaken":{"value":{"type":"urn:lunedo:problem:portalDomainTaken","title":"Another knowledge base uses this domain","status":409,"code":"portalDomainTaken"}},"portalPathTaken":{"value":{"type":"urn:lunedo:problem:portalPathTaken","title":"Another knowledge base uses this path","status":409,"code":"portalPathTaken"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/knowledge-base/portal/appearance":{"put":{"operationId":"portal.setAppearance","summary":"Change the appearance of a portal","description":"Changes the brand color, the start page and the footer. An own color must reach the contrast WCAG AA asks for in light and dark mode; otherwise the answer `brandContrast` contains the nearest passing shades, which `confirmProposal` saves.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"brand":{"type":"object","properties":{"color":{"type":"string","enum":["petrol","blue","violet","amber","red","green","gray","custom"],"description":"A color of the fixed palette, or `custom` for own values."},"light":{"anyOf":[{"type":"string","maxLength":7,"description":"A color as a hex value such as `#0B6F78`."},{"type":"null"}],"description":"Own color for light mode, or null for a palette color."},"dark":{"anyOf":[{"type":"string","maxLength":7,"description":"A color as a hex value such as `#0B6F78`."},{"type":"null"}],"description":"Own color for dark mode, or null for a palette color."}},"required":["color","light","dark"],"additionalProperties":false,"description":"The brand color of the portal."},"confirmProposal":{"description":"Saves the proposed shades when the own color does not reach the contrast WCAG AA asks for.","type":"boolean"},"welcomeHeading":{"description":"Heading of the start page.","type":"string","maxLength":120},"welcomeText":{"description":"Short text below the heading.","type":"string","maxLength":400},"topBarThreshold":{"description":"Not used any more; accepted so that existing clients keep working.","type":"integer","minimum":1,"maximum":100},"poweredBy":{"description":"Shows “Made with Lunedo” in the footer.","type":"boolean"},"feedbackRetentionMonths":{"description":"Months after which readers' notes are deleted.","type":"integer","minimum":1,"maximum":60}},"additionalProperties":false,"description":"Fields to change. Fields that are left out stay as they are."},"example":{"brand":{"color":"custom","light":"#1F4E99","dark":"#8AA8E6"}}}}},"responses":{"200":{"description":"The portal after the change.","content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"ID of the knowledge base."},"path":{"type":"string","description":"Path under `/help/` on the instance."},"domain":{"description":"Own domain of the portal, or null.","type":["string","null"]},"url":{"type":"string","description":"Address of the portal's start page."},"brand":{"type":"object","properties":{"color":{"type":"string","enum":["petrol","blue","violet","amber","red","green","gray","custom"],"description":"A color of the fixed palette, or `custom` for own values."},"light":{"anyOf":[{"type":"string","maxLength":7,"description":"A color as a hex value such as `#0B6F78`."},{"type":"null"}],"description":"Own color for light mode, or null for a palette color."},"dark":{"anyOf":[{"type":"string","maxLength":7,"description":"A color as a hex value such as `#0B6F78`."},{"type":"null"}],"description":"Own color for dark mode, or null for a palette color."}},"required":["color","light","dark"],"additionalProperties":false,"description":"The brand color of the portal."},"colors":{"type":"object","properties":{"light":{"type":"string","description":"Light mode."},"dark":{"type":"string","description":"Dark mode."}},"required":["light","dark"],"additionalProperties":false,"description":"The brand colors the portal uses."},"welcomeHeading":{"type":"string","description":"Heading of the start page; empty for the default heading."},"welcomeText":{"type":"string","description":"Short text below the heading; may be empty."},"topBarThreshold":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Not used any more: the top bar always shows a single menu of all areas. Kept so that existing clients keep working."},"poweredBy":{"type":"boolean","description":"Whether the footer says that the portal is made with Lunedo."},"feedbackRetentionMonths":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Months after which readers' notes on articles are deleted."},"logoRef":{"description":"Reference of the uploaded logo, or null.","type":["string","null"]}},"required":["spaceId","path","domain","url","brand","colors","welcomeHeading","welcomeText","topBarThreshold","poweredBy","feedbackRetentionMonths","logoRef"],"additionalProperties":false,"description":"Address and appearance of a knowledge base portal."},"example":{"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","path":"help","domain":null,"url":"https://wiki.example.org/help/help/","brand":{"color":"petrol","light":null,"dark":null},"colors":{"light":"#0B6F78","dark":"#5DB9C2"},"welcomeHeading":"","welcomeText":"","topBarThreshold":10,"poweredBy":true,"feedbackRetentionMonths":12,"logoRef":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidBrandColor`: The brand color is not valid. `invalidInput`: The request is not valid. `invalidRetention`: The retention period is not valid. `invalidTopBarThreshold`: The number of categories is not valid. `invalidWelcome`: The start page text is too long.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidBrandColor":{"value":{"type":"urn:lunedo:problem:invalidBrandColor","title":"The brand color is not valid","status":400,"code":"invalidBrandColor"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidRetention":{"value":{"type":"urn:lunedo:problem:invalidRetention","title":"The retention period is not valid","status":400,"code":"invalidRetention"}},"invalidTopBarThreshold":{"value":{"type":"urn:lunedo:problem:invalidTopBarThreshold","title":"The number of categories is not valid","status":400,"code":"invalidTopBarThreshold"}},"invalidWelcome":{"value":{"type":"urn:lunedo:problem:invalidWelcome","title":"The start page text is too long","status":400,"code":"invalidWelcome"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`brandContrast`: The color does not reach the required contrast.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"brandContrast":{"value":{"type":"urn:lunedo:problem:brandContrast","title":"The color does not reach the required contrast","status":409,"code":"brandContrast"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/knowledge-base/portal/domains":{"get":{"operationId":"portal.spaceDomains","summary":"List the domains a portal can use","description":"Domains the instance administrators allowed for the organization of the knowledge base that are free or used by this knowledge base. Domains of other knowledge bases are left out.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The domains.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"domain":{"type":"string","description":"The domain name."},"organizationId":{"type":"string","format":"uuid","description":"ID of the organization that may use the domain."},"organizationName":{"type":"string","description":"Name of the organization."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the knowledge base that uses the domain."},"spaceName":{"description":"Name of the knowledge base that uses the domain.","type":["string","null"]},"createdAt":{"type":"string","format":"date-time","description":"When the domain was allowed. ISO 8601 timestamp in UTC."}},"required":["domain","organizationId","organizationName","spaceId","spaceName","createdAt"],"additionalProperties":false,"description":"A domain allowed for knowledge base portals."}},"example":[{"domain":"help.example.org","organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a30","organizationName":"Example","spaceId":null,"spaceName":null,"createdAt":"2026-10-19T08:00:00.000Z"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/knowledge-base/portal/logo":{"delete":{"operationId":"portal.removeLogo","summary":"Remove the logo of a portal","description":"The portal shows the organization's logo again, or the first letter of its name.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The portal after the change.","content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"ID of the knowledge base."},"path":{"type":"string","description":"Path under `/help/` on the instance."},"domain":{"description":"Own domain of the portal, or null.","type":["string","null"]},"url":{"type":"string","description":"Address of the portal's start page."},"brand":{"type":"object","properties":{"color":{"type":"string","enum":["petrol","blue","violet","amber","red","green","gray","custom"],"description":"A color of the fixed palette, or `custom` for own values."},"light":{"anyOf":[{"type":"string","maxLength":7,"description":"A color as a hex value such as `#0B6F78`."},{"type":"null"}],"description":"Own color for light mode, or null for a palette color."},"dark":{"anyOf":[{"type":"string","maxLength":7,"description":"A color as a hex value such as `#0B6F78`."},{"type":"null"}],"description":"Own color for dark mode, or null for a palette color."}},"required":["color","light","dark"],"additionalProperties":false,"description":"The brand color of the portal."},"colors":{"type":"object","properties":{"light":{"type":"string","description":"Light mode."},"dark":{"type":"string","description":"Dark mode."}},"required":["light","dark"],"additionalProperties":false,"description":"The brand colors the portal uses."},"welcomeHeading":{"type":"string","description":"Heading of the start page; empty for the default heading."},"welcomeText":{"type":"string","description":"Short text below the heading; may be empty."},"topBarThreshold":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Not used any more: the top bar always shows a single menu of all areas. Kept so that existing clients keep working."},"poweredBy":{"type":"boolean","description":"Whether the footer says that the portal is made with Lunedo."},"feedbackRetentionMonths":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Months after which readers' notes on articles are deleted."},"logoRef":{"description":"Reference of the uploaded logo, or null.","type":["string","null"]}},"required":["spaceId","path","domain","url","brand","colors","welcomeHeading","welcomeText","topBarThreshold","poweredBy","feedbackRetentionMonths","logoRef"],"additionalProperties":false,"description":"Address and appearance of a knowledge base portal."},"example":{"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","path":"help","domain":null,"url":"https://wiki.example.org/help/help/","brand":{"color":"petrol","light":null,"dark":null},"colors":{"light":"#0B6F78","dark":"#5DB9C2"},"welcomeHeading":"","welcomeText":"","topBarThreshold":10,"poweredBy":true,"feedbackRetentionMonths":12,"logoRef":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"put":{"operationId":"portal.uploadLogo","summary":"Upload the logo of a portal","description":"Sets the logo in the top bar and on the sign-in page of the portal. PNG, JPEG or WebP, at most 256 KiB.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contentType":{"type":"string","enum":["image/png","image/jpeg","image/webp"],"description":"Type of the image."},"data":{"type":"string","maxLength":349528,"format":"base64","contentEncoding":"base64","pattern":"^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$","description":"The image, Base64-encoded."}},"required":["contentType","data"],"additionalProperties":false,"description":"A logo image."},"example":{"contentType":"image/png","data":"iVBORw0KGgo="}}}},"responses":{"200":{"description":"The portal after the change.","content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"ID of the knowledge base."},"path":{"type":"string","description":"Path under `/help/` on the instance."},"domain":{"description":"Own domain of the portal, or null.","type":["string","null"]},"url":{"type":"string","description":"Address of the portal's start page."},"brand":{"type":"object","properties":{"color":{"type":"string","enum":["petrol","blue","violet","amber","red","green","gray","custom"],"description":"A color of the fixed palette, or `custom` for own values."},"light":{"anyOf":[{"type":"string","maxLength":7,"description":"A color as a hex value such as `#0B6F78`."},{"type":"null"}],"description":"Own color for light mode, or null for a palette color."},"dark":{"anyOf":[{"type":"string","maxLength":7,"description":"A color as a hex value such as `#0B6F78`."},{"type":"null"}],"description":"Own color for dark mode, or null for a palette color."}},"required":["color","light","dark"],"additionalProperties":false,"description":"The brand color of the portal."},"colors":{"type":"object","properties":{"light":{"type":"string","description":"Light mode."},"dark":{"type":"string","description":"Dark mode."}},"required":["light","dark"],"additionalProperties":false,"description":"The brand colors the portal uses."},"welcomeHeading":{"type":"string","description":"Heading of the start page; empty for the default heading."},"welcomeText":{"type":"string","description":"Short text below the heading; may be empty."},"topBarThreshold":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Not used any more: the top bar always shows a single menu of all areas. Kept so that existing clients keep working."},"poweredBy":{"type":"boolean","description":"Whether the footer says that the portal is made with Lunedo."},"feedbackRetentionMonths":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Months after which readers' notes on articles are deleted."},"logoRef":{"description":"Reference of the uploaded logo, or null.","type":["string","null"]}},"required":["spaceId","path","domain","url","brand","colors","welcomeHeading","welcomeText","topBarThreshold","poweredBy","feedbackRetentionMonths","logoRef"],"additionalProperties":false,"description":"Address and appearance of a knowledge base portal."},"example":{"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","path":"help","domain":null,"url":"https://wiki.example.org/help/help/","brand":{"color":"petrol","light":null,"dark":null},"colors":{"light":"#0B6F78","dark":"#5DB9C2"},"welcomeHeading":"","welcomeText":"","topBarThreshold":10,"poweredBy":true,"feedbackRetentionMonths":12,"logoRef":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidLogo`: The logo is not a supported image.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidLogo":{"value":{"type":"urn:lunedo:problem:invalidLogo","title":"The logo is not a supported image","status":400,"code":"invalidLogo"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/knowledge-base/required-sections":{"put":{"operationId":"knowledgeBases.setRequired","summary":"Make a template section required or optional","description":"A required section must contain text, an image or other content before an article from this template can be published. Published articles stay published. By default nothing is required.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"templateId":{"type":"string","maxLength":100,"description":"ID of the template."},"sectionKey":{"type":"string","maxLength":40,"description":"Key of the section."},"required":{"type":"boolean","description":"Whether the section must contain text before an article is published."}},"required":["templateId","sectionKey","required"],"additionalProperties":false,"description":"Whether a section is required."},"example":{"templateId":"builtin:article-how-to","sectionKey":"steps","required":true}}}},"responses":{"200":{"description":"The templates after the change.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"templateId":{"type":"string","description":"ID of the template."},"name":{"type":"string","description":"Name of the template."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Type the template gives its articles, or null."},"builtIn":{"type":"boolean","description":"Whether the template ships with Lunedo."},"sections":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the section."},"title":{"type":"string","description":"Heading of the section."},"icon":{"description":"Name of a Lucide icon, or null.","type":["string","null"]},"required":{"type":"boolean","description":"Whether articles from this template can only be published with text in this section."}},"required":["key","title","icon","required"],"additionalProperties":false,"description":"A section of the template."},"description":"Sections of the template in order."}},"required":["templateId","name","articleType","builtIn","sections"],"additionalProperties":false,"description":"An article template of the knowledge base."},"description":"Article templates of the knowledge base."},"example":[{"templateId":"builtin:article-how-to","name":"How-to","articleType":"howTo","builtIn":true,"sections":[{"key":"steps","title":"Steps","icon":"list-ordered","required":true}]}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `sectionNotFound`: The section does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"sectionNotFound":{"value":{"type":"urn:lunedo:problem:sectionNotFound","title":"The section does not exist","status":404,"code":"sectionNotFound"}}}}}},"409":{"description":"`notKnowledgeBase`: The space is not a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/knowledge-base/reviews":{"get":{"operationId":"reviews.settings","summary":"Get the review settings of a knowledge base","description":"Returns the default review interval, the reminder lead time and who is reminded.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Knowledge base reviews"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The settings.","content":{"application/json":{"schema":{"type":"object","properties":{"intervalMonths":{"anyOf":[{"anyOf":[{"type":"number","const":3},{"type":"number","const":6},{"type":"number","const":12}],"description":"Review interval in months."},{"type":"null"}],"description":"Interval for every article without its own, or null when reviews are off."},"leadDays":{"anyOf":[{"type":"number","const":0},{"type":"number","const":7},{"type":"number","const":14},{"type":"number","const":30}],"description":"Days before the due date at which owners get a first reminder. 0 sends only the one on the due date."},"recipients":{"type":"string","enum":["owner","ownerAndAdministrators"],"description":"Who is reminded: `owner`, or `ownerAndAdministrators` for the owner and the space admins. Articles without an owner always go to the space admins."}},"required":["intervalMonths","leadDays","recipients"],"additionalProperties":false,"description":"Review settings of a knowledge base."},"example":{"intervalMonths":6,"leadDays":14,"recipients":"owner"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notKnowledgeBase`: The space is not a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"put":{"operationId":"reviews.updateSettings","summary":"Change the review settings of a knowledge base","description":"Changes the default interval, the lead time or who is reminded. Due dates and reminders of every article follow at once. Audited.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Knowledge base reviews"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"intervalMonths":{"description":"New interval, or null to switch reviews off.","anyOf":[{"anyOf":[{"type":"number","const":3},{"type":"number","const":6},{"type":"number","const":12}],"description":"Review interval in months."},{"type":"null"}]},"leadDays":{"anyOf":[{"type":"number","const":0},{"type":"number","const":7},{"type":"number","const":14},{"type":"number","const":30}],"description":"Days before the due date at which owners get a first reminder. 0 sends only the one on the due date."},"recipients":{"type":"string","enum":["owner","ownerAndAdministrators"],"description":"Who is reminded: `owner`, or `ownerAndAdministrators` for the owner and the space admins. Articles without an owner always go to the space admins."}},"additionalProperties":false,"description":"Settings to change. Fields that are left out keep their value."},"example":{"intervalMonths":6}}}},"responses":{"200":{"description":"The settings after the change.","content":{"application/json":{"schema":{"type":"object","properties":{"intervalMonths":{"anyOf":[{"anyOf":[{"type":"number","const":3},{"type":"number","const":6},{"type":"number","const":12}],"description":"Review interval in months."},{"type":"null"}],"description":"Interval for every article without its own, or null when reviews are off."},"leadDays":{"anyOf":[{"type":"number","const":0},{"type":"number","const":7},{"type":"number","const":14},{"type":"number","const":30}],"description":"Days before the due date at which owners get a first reminder. 0 sends only the one on the due date."},"recipients":{"type":"string","enum":["owner","ownerAndAdministrators"],"description":"Who is reminded: `owner`, or `ownerAndAdministrators` for the owner and the space admins. Articles without an owner always go to the space admins."}},"required":["intervalMonths","leadDays","recipients"],"additionalProperties":false,"description":"Review settings of a knowledge base."},"example":{"intervalMonths":6,"leadDays":14,"recipients":"owner"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notKnowledgeBase`: The space is not a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/knowledge-base/templates":{"get":{"operationId":"knowledgeBases.templates","summary":"List the article templates with their sections","description":"Lists the templates articles of the knowledge base can start from, with the sections that are required.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The templates.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"templateId":{"type":"string","description":"ID of the template."},"name":{"type":"string","description":"Name of the template."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Type the template gives its articles, or null."},"builtIn":{"type":"boolean","description":"Whether the template ships with Lunedo."},"sections":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the section."},"title":{"type":"string","description":"Heading of the section."},"icon":{"description":"Name of a Lucide icon, or null.","type":["string","null"]},"required":{"type":"boolean","description":"Whether articles from this template can only be published with text in this section."}},"required":["key","title","icon","required"],"additionalProperties":false,"description":"A section of the template."},"description":"Sections of the template in order."}},"required":["templateId","name","articleType","builtIn","sections"],"additionalProperties":false,"description":"An article template of the knowledge base."},"description":"Article templates of the knowledge base."},"example":[{"templateId":"builtin:article-how-to","name":"How-to","articleType":"howTo","builtIn":true,"sections":[{"key":"steps","title":"Steps","icon":"list-ordered","required":true}]}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notKnowledgeBase`: The space is not a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/labels":{"get":{"operationId":"items.suggestLabels","summary":"Suggest labels","description":"Suggests labels used in readable spaces of the same organization, most used first. For a personal space, labels of readable personal spaces.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Pages"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"q","in":"query","required":false,"description":"Start of the label.","schema":{"default":"","type":"string","maxLength":100}}],"responses":{"200":{"description":"Suggested labels.","content":{"application/json":{"schema":{"type":"array","items":{"type":"string","description":"A label, lowercase, up to 100 characters."},"description":"Labels, sorted."},"example":["runbook","release-notes"]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/labels/{label}/pages":{"get":{"operationId":"items.pagesWithLabel","summary":"List the pages with a label","description":"Lists the pages of the space that carry the label.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Pages"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"label","in":"path","required":true,"description":"The label.","schema":{"type":"string","maxLength":200}}],"responses":{"200":{"description":"Pages with the label.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"ID of the page."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the page in the addresses of the app."},"title":{"type":"string","description":"Title of the page."},"parents":{"type":"array","items":{"type":"string","description":"Title of a parent."},"description":"Titles of the parents the caller can read, from the top down."},"contentUpdatedAt":{"type":"string","format":"date-time","description":"When its content last changed. ISO 8601 timestamp in UTC."}},"required":["itemId","number","title","parents","contentUpdatedAt"],"additionalProperties":false,"description":"A page with the label."},"description":"Pages with the label, ordered by title."},"example":[{"itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"title":"VPN access for remote staff","parents":["Network"],"contentUpdatedAt":"2026-10-05T08:10:00.000Z"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/meeting-series":{"get":{"operationId":"meetings.listSeries","summary":"List the meeting series of a space","description":"Lists the series of the space the caller can read: running series first, then ended ones.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The series.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the series."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the series in the addresses of the app."},"title":{"type":"string","description":"Name."},"archived":{"type":"boolean","description":"Whether the series has ended."},"upcomingAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start of the next meeting, or null. ISO 8601 timestamp in UTC."}},"required":["id","number","title","archived","upcomingAt"],"additionalProperties":false,"description":"A series of the space."},"description":"The meeting series of the space the caller can see."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a00","number":1050,"title":"Jour fixe IT","archived":false,"upcomingAt":"2026-10-12T07:30:00.000Z"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"meetings.createSeries","summary":"Create a meeting series","description":"Creates a series with its members, schedule and template, and its first meeting. Without a fixed rhythm the first meeting takes place at `startsOn` and `startTime`.\n\nRequires the permission `space.edit` on the space in `spaceId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"space.edit","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":400,"description":"Name of the series, 1 to 200 characters."},"parentId":{"default":null,"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Page or folder to place the series below, or null for the top level."},"members":{"default":[],"description":"Members of the series: the default attendees of every meeting. Access comes from the space roles.","maxItems":100,"type":"array","items":{"type":"string","format":"uuid","description":"Account ID."}},"templateId":{"default":"builtin:team-meeting","description":"Template for the meeting pages: a template ID or `builtin:<key>`.","type":"string","maxLength":64},"reminder":{"default":"oneDay","type":"string","enum":["off","oneDay","twoDays","oneWeek"],"description":"When attendees are reminded to add their topics: `off`, or one day, two days or one week before each meeting."},"rhythm":{"type":"object","properties":{"frequency":{"type":"string","enum":["none","daily","weekly","monthly","yearly"],"description":"`none` for no fixed rhythm, otherwise how often the meetings repeat."},"interval":{"default":1,"description":"Every how many days, weeks, months or years. 2 weekly is every two weeks, 3 monthly is quarterly.","type":"integer","minimum":1,"maximum":52},"weekdays":{"description":"For `weekly`: the weekdays of the meetings, at least one.","maxItems":7,"type":"array","items":{"type":"string","enum":["MO","TU","WE","TH","FR","SA","SU"],"description":"Weekday as in iCalendar: `MO` to `SU`."}},"monthDay":{"description":"For `monthly` by date: the day of the month.","type":"integer","minimum":1,"maximum":31},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"For `monthly` by weekday: the weekday, for example `TU`.","type":"string","enum":["MO","TU","WE","TH","FR","SA","SU"]}},"required":["frequency"],"additionalProperties":false,"description":"The rhythm of a series, as the interface offers it."},"startsOn":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Date of the first meeting in the series' time zone, YYYY-MM-DD."},"startTime":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$","description":"Local start time of the meetings, HH:MM in 24 hours."},"timeZone":{"type":"string","minLength":1,"maxLength":64,"description":"IANA time zone of the series, such as `Europe/Vienna`. Meetings keep their local time across daylight saving changes."},"durationMinutes":{"type":"integer","minimum":5,"maximum":1440,"description":"Duration of each meeting in minutes."}},"required":["name","rhythm","startsOn","startTime","timeZone","durationMinutes"],"additionalProperties":false,"description":"A new meeting series."},"example":{"name":"Jour fixe IT","parentId":null,"members":["01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20"],"templateId":"builtin:team-meeting","rhythm":{"frequency":"weekly","interval":1,"weekdays":["MO"]},"startsOn":"2026-10-12","startTime":"09:30","timeZone":"Europe/Vienna","durationMinutes":45}}}},"responses":{"201":{"description":"The new series.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the series."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the series in the addresses of the app."},"spaceId":{"type":"string","format":"uuid","description":"Space of the series."},"title":{"type":"string","description":"Name of the series."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Parent page or folder, or null."},"archived":{"type":"boolean","description":"True when the series has ended: read-only, without a next meeting."},"oneOnOne":{"type":"boolean","description":"True for the series of a one-on-one."},"members":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null without one. Changes whenever the picture changes; load the picture from `GET /api/v1/accounts/{accountId}/picture`.","type":["string","null"]},"active":{"type":"boolean","description":"Whether the person can still take part: false when the account is deactivated, not set up yet or no longer a member of the organization. Always true for people the caller may not see."},"canRead":{"type":"boolean","description":"Whether the person can read the series. Active members without access are shown with a warning."}},"required":["id","name","pictureRef","active","canRead"],"additionalProperties":false,"description":"A member of the series."},"description":"Members in their order."},"schedule":{"type":"object","properties":{"rhythm":{"anyOf":[{"type":"object","properties":{"frequency":{"type":"string","description":"How often the meetings repeat. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays for weekly rhythms.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month for monthly rhythms by date.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"1 to 4 or -1 for monthly rhythms by weekday.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekday":{"description":"Weekday for monthly rhythms by weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"The rhythm of the series."},{"type":"null"}],"description":"The rhythm, or null when the rule cannot be shown as one."},"recurrence":{"description":"The iCalendar recurrence rule (RFC 5545) without `RRULE:`, or null without a fixed rhythm.","type":["string","null"]},"startsOn":{"type":"string","description":"Date of the first meeting."},"startTime":{"type":"string","description":"Local start time."},"timeZone":{"type":"string","description":"Time zone of the series."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Duration in minutes."}},"required":["rhythm","recurrence","startsOn","startTime","timeZone","durationMinutes"],"additionalProperties":false,"description":"The schedule."},"template":{"type":"object","properties":{"id":{"type":"string","description":"Template ID."},"name":{"description":"Name of the template, or null when it was deleted.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"Template of the meeting pages."},"reminder":{"type":"string","description":"When attendees are reminded to add their topics: `off`, or one day, two days or one week before each meeting. New values can be added in later versions; handle unknown values.","x-extensible-enum":["off","oneDay","twoDays","oneWeek"]},"source":{"type":"string","description":"Where the schedule comes from: set here or from a calendar. New values can be added in later versions; handle unknown values.","x-extensible-enum":["manual","calendar"]},"calendarUid":{"description":"Calendar UID when the schedule comes from a calendar.","type":["string","null"]},"upcoming":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the meeting page."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the meeting page in the addresses of the app."},"title":{"type":"string","description":"Title of the meeting page."},"state":{"type":"string","description":"`upcoming` is the next meeting, `closed` and `skipped` are done, `reopened` was closed and is open again. New values can be added in later versions; handle unknown values.","x-extensible-enum":["upcoming","closed","reopened","skipped"]},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start of the meeting, or null when it is not scheduled yet. ISO 8601 timestamp in UTC."},"recurrenceId":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Original start of the occurrence in the rhythm, or null. ISO 8601 timestamp in UTC."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Duration in minutes."},"attendees":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of attendees."},"present":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of attendees marked present."},"extra":{"type":"boolean","description":"True for an additional meeting outside the rhythm."},"next":{"type":"boolean","description":"True for the next meeting of the series: the earliest one that is neither held nor skipped."}},"required":["id","number","title","state","startsAt","recurrenceId","durationMinutes","attendees","present","extra","next"],"additionalProperties":false,"description":"A meeting of a series."},{"type":"null"}],"description":"The next meeting, or null when the series has ended."},"openTopics":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Open running topics the caller can see."},"overview":{"type":"object","properties":{"columns":{"minItems":2,"maxItems":2,"type":"array","items":{"type":"array","items":{"type":"string","description":"A module of the series overview. New values can be added in later versions; handle unknown values.","x-extensible-enum":["topics","tasks","decisions","meetings","attendance","links"]}},"description":"Modules of the left and the right column, from top to bottom."},"hidden":{"type":"array","items":{"type":"string","description":"A module of the series overview. New values can be added in later versions; handle unknown values.","x-extensible-enum":["topics","tasks","decisions","meetings","attendance","links"]},"description":"Modules that are not shown."},"links":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the item."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app."},"title":{"type":"string","description":"Title of the item."},"kind":{"type":"string","description":"Kind of the item, such as `page` or `folder`."},"spaceKey":{"type":"string","description":"Key of its space."}},"required":["id","number","title","kind","spaceKey"],"additionalProperties":false,"description":"A pinned item."},"description":"Pinned items for the Links module that the caller can open, in their order."}},"required":["columns","hidden","links"],"additionalProperties":false,"description":"The overview of the series, the same for all members."},"createdAt":{"type":"string","format":"date-time","description":"When the series was created. ISO 8601 timestamp in UTC."}},"required":["id","number","spaceId","title","parentId","archived","oneOnOne","members","schedule","template","reminder","source","calendarUid","upcoming","openTopics","overview","createdAt"],"additionalProperties":false,"description":"A meeting series."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a00","number":1050,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a00","title":"Jour fixe IT","parentId":null,"archived":false,"oneOnOne":false,"members":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger","pictureRef":null,"active":true,"canRead":true}],"schedule":{"rhythm":{"frequency":"weekly","interval":1,"weekdays":["MO"]},"recurrence":"FREQ=WEEKLY;BYDAY=MO","startsOn":"2026-10-12","startTime":"09:30","timeZone":"Europe/Vienna","durationMinutes":45},"template":{"id":"builtin:team-meeting","name":"Team meeting"},"reminder":"oneDay","source":"manual","calendarUid":null,"upcoming":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a10","number":1051,"title":"Jour fixe IT · 12 Oct 2026","state":"upcoming","startsAt":"2026-10-12T07:30:00.000Z","recurrenceId":"2026-10-12T07:30:00.000Z","durationMinutes":45,"attendees":5,"present":0,"extra":false,"next":true},"openTopics":3,"overview":{"columns":[["topics","tasks"],["meetings","decisions"]],"hidden":["attendance","links"],"links":[]},"createdAt":"2026-10-05T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidDuration`: The duration is not valid. `invalidInput`: The request is not valid. `invalidMember`: The person cannot take part. `invalidPlacement`: The place in the page tree is not valid. `invalidRhythm`: The rhythm is not valid. `invalidSchedule`: The schedule is not valid. `invalidTimeZone`: The time zone is not known. `invalidTitle`: The title is not valid. `tooManyMembers`: The series has too many members.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidDuration":{"value":{"type":"urn:lunedo:problem:invalidDuration","title":"The duration is not valid","status":400,"code":"invalidDuration"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidMember":{"value":{"type":"urn:lunedo:problem:invalidMember","title":"The person cannot take part","status":400,"code":"invalidMember"}},"invalidPlacement":{"value":{"type":"urn:lunedo:problem:invalidPlacement","title":"The place in the page tree is not valid","status":400,"code":"invalidPlacement"}},"invalidRhythm":{"value":{"type":"urn:lunedo:problem:invalidRhythm","title":"The rhythm is not valid","status":400,"code":"invalidRhythm"}},"invalidSchedule":{"value":{"type":"urn:lunedo:problem:invalidSchedule","title":"The schedule is not valid","status":400,"code":"invalidSchedule"}},"invalidTimeZone":{"value":{"type":"urn:lunedo:problem:invalidTimeZone","title":"The time zone is not known","status":400,"code":"invalidTimeZone"}},"invalidTitle":{"value":{"type":"urn:lunedo:problem:invalidTitle","title":"The title is not valid","status":400,"code":"invalidTitle"}},"tooManyMembers":{"value":{"type":"urn:lunedo:problem:tooManyMembers","title":"The series has too many members","status":400,"code":"tooManyMembers"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `templateNotFound`: The template does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"templateNotFound":{"value":{"type":"urn:lunedo:problem:templateNotFound","title":"The template does not exist","status":404,"code":"templateNotFound"}}}}}},"409":{"description":"`knowledgeBaseContent`: A knowledge base holds only articles and categories.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"knowledgeBaseContent":{"value":{"type":"urn:lunedo:problem:knowledgeBaseContent","title":"A knowledge base holds only articles and categories","status":409,"code":"knowledgeBaseContent"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/newest-content":{"get":{"operationId":"reports.newestContent","summary":"List the newest pages and blog posts of a space","description":"Lists the pages and blog posts of a space that the caller can read, most recently changed first, as the news on the space overview shows them. Archived and deleted content is left out.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Reports"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"description":"Maximum number of entries, 1 to 50. The default is 5.","schema":{"default":5,"type":"integer","minimum":1,"maximum":50}}],"responses":{"200":{"description":"The pages and blog posts.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the page or blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the content in the addresses of the app."},"kind":{"type":"string","description":"`page` or `blogPost`. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","blogPost"]},"title":{"type":"string","description":"Title."},"path":{"type":"string","description":"Path in the web interface."},"author":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the person."},"name":{"type":"string","description":"Name of the person."}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who created it, or null when unknown or not visible to the caller."},"contentUpdatedAt":{"type":"string","format":"date-time","description":"When its content last changed. ISO 8601 timestamp in UTC."}},"required":["id","number","kind","title","path","author","contentUpdatedAt"],"additionalProperties":false,"description":"A recently changed page or blog post."},"description":"Content, most recently changed first."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5c11","number":1051,"kind":"page","title":"VPN access for remote staff","path":"/spaces/ITOPS/pages/1042/vpn-access-for-remote-staff","author":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"contentUpdatedAt":"2026-10-05T08:10:00.000Z"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/one-on-one/successor":{"post":{"operationId":"oneOnOnes.successor","summary":"Change a person of a one-on-one","description":"For the remaining person: `add` makes the successor space admin and member of the series and removes the previous person; the successor sees all earlier meetings. `new` starts a new one-on-one with the successor and leaves this one unchanged.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["One-on-ones"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"The confidential space of the one-on-one.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"previousId":{"type":"string","format":"uuid","description":"The person who leaves the one-on-one."},"successorId":{"type":"string","format":"uuid","description":"The person who follows."},"mode":{"type":"string","enum":["add","new"],"description":"`add` adds the successor to this one-on-one, who then sees all earlier meetings; `new` starts a new one-on-one."}},"required":["previousId","successorId","mode"],"additionalProperties":false,"description":"A change of person in a one-on-one."},"example":{"previousId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","successorId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a21","mode":"add"}}}},"responses":{"200":{"description":"The one-on-one that continues.","content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"The confidential space."},"seriesId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The series."},"seriesNumber":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the series in the addresses of the app."}},"required":["spaceId","seriesId","seriesNumber"],"additionalProperties":false,"description":"The one-on-one."},"example":{"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5b00","seriesId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a00","seriesNumber":1050}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid. `invalidMember`: The person cannot take part.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidMember":{"value":{"type":"urn:lunedo:problem:invalidMember","title":"The person cannot take part","status":400,"code":"invalidMember"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `notOneOnOneMember`: Only the remaining person can change the one-on-one.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"notOneOnOneMember":{"value":{"type":"urn:lunedo:problem:notOneOnOneMember","title":"Only the remaining person can change the one-on-one","status":403,"code":"notOneOnOneMember"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`noSharedOrganization`: The two people share no organization. `notOneOnOne`: The space is not a one-on-one.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"noSharedOrganization":{"value":{"type":"urn:lunedo:problem:noSharedOrganization","title":"The two people share no organization","status":409,"code":"noSharedOrganization"}},"notOneOnOne":{"value":{"type":"urn:lunedo:problem:notOneOnOne","title":"The space is not a one-on-one","status":409,"code":"notOneOnOne"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/page-statuses":{"get":{"operationId":"ownership.statuses","summary":"List the page status values of a space","description":"Returns whether page status is turned on and the values editors can choose, in order.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Ownership and status"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The values.","content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether page status is turned on in the space."},"values":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the status value."},"builtIn":{"anyOf":[{"type":"string","x-extensible-enum":["roughDraft","inProgress","readyForReview","verified"]},{"type":"null"}],"description":"Which default value this is, or null for a value a space admin added. Clients show the translated name of a default value unless `name` is set. New values can be added in later versions; handle unknown values."},"name":{"description":"Name set by a space admin, or null to show the default name.","type":["string","null"]},"color":{"type":"string","enum":["neutral","accent","info","success","warning","danger"],"description":"Color of the status: `neutral`, `accent`, `info`, `success`, `warning` or `danger`."},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Place in the list, starting at 0."},"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of pages with this status that the caller can view, without pages in the trash."}},"required":["id","builtIn","name","color","position","pages"],"additionalProperties":false,"description":"A status value of a space."},"description":"Values in their order."}},"required":["enabled","values"],"additionalProperties":false,"description":"The page status values of a space."},"example":{"enabled":true,"values":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","builtIn":"verified","name":null,"color":"success","position":3,"pages":12}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"ownership.addStatus","summary":"Add a page status value","description":"Adds a value at the end of the list. A space can have up to 20 values.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Ownership and status"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":200,"description":"Name, 1 to 40 characters, unique in the space."},"color":{"type":"string","enum":["neutral","accent","info","success","warning","danger"],"description":"Color of the status: `neutral`, `accent`, `info`, `success`, `warning` or `danger`."}},"required":["name","color"],"additionalProperties":false,"description":"A new status value."},"example":{"name":"Outdated","color":"danger"}}}},"responses":{"201":{"description":"The new value.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the status value."},"builtIn":{"anyOf":[{"type":"string","x-extensible-enum":["roughDraft","inProgress","readyForReview","verified"]},{"type":"null"}],"description":"Which default value this is, or null for a value a space admin added. Clients show the translated name of a default value unless `name` is set. New values can be added in later versions; handle unknown values."},"name":{"description":"Name set by a space admin, or null to show the default name.","type":["string","null"]},"color":{"type":"string","enum":["neutral","accent","info","success","warning","danger"],"description":"Color of the status: `neutral`, `accent`, `info`, `success`, `warning` or `danger`."},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Place in the list, starting at 0."},"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of pages with this status that the caller can view, without pages in the trash."}},"required":["id","builtIn","name","color","position","pages"],"additionalProperties":false,"description":"A status value of a space."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","builtIn":"verified","name":null,"color":"success","position":3,"pages":12}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidStatus`: The status is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidStatus":{"value":{"type":"urn:lunedo:problem:invalidStatus","title":"The status is not valid","status":400,"code":"invalidStatus"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`statusExists`: A status with this name exists already. `tooManyStatusValues`: The space has too many status values.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"statusExists":{"value":{"type":"urn:lunedo:problem:statusExists","title":"A status with this name exists already","status":409,"code":"statusExists"}},"tooManyStatusValues":{"value":{"type":"urn:lunedo:problem:tooManyStatusValues","title":"The space has too many status values","status":409,"code":"tooManyStatusValues"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/page-statuses/{statusId}":{"delete":{"operationId":"ownership.removeStatus","summary":"Remove a page status value","description":"Removes the value. Pages with it lose their status. Send the number of affected pages you confirmed; when it no longer matches, nothing is removed.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Ownership and status"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"statusId","in":"path","required":true,"description":"ID of the status value.","schema":{"type":"string","format":"uuid"}},{"name":"pages","in":"query","required":false,"description":"Number of pages that lose the status, as shown to the person who confirmed. When it differs, nothing is removed and the answer `statusInUse` names the current number.","schema":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `statusNotFound`: The status does not exist anymore.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"statusNotFound":{"value":{"type":"urn:lunedo:problem:statusNotFound","title":"The status does not exist anymore","status":404,"code":"statusNotFound"}}}}}},"409":{"description":"`statusInUse`: Pages use this status.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"statusInUse":{"value":{"type":"urn:lunedo:problem:statusInUse","title":"Pages use this status","status":409,"code":"statusInUse"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"patch":{"operationId":"ownership.updateStatus","summary":"Change a page status value","description":"Renames a value or changes its color. Pages with the value show the change at once.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Ownership and status"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"statusId","in":"path","required":true,"description":"ID of the status value.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":200,"description":"Name, 1 to 40 characters, unique in the space."},"color":{"type":"string","enum":["neutral","accent","info","success","warning","danger"],"description":"Color of the status: `neutral`, `accent`, `info`, `success`, `warning` or `danger`."}},"additionalProperties":false,"description":"Changes to a status value. Renaming a default value replaces its translated name."},"example":{"name":"Approved"}}}},"responses":{"200":{"description":"The changed value.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the status value."},"builtIn":{"anyOf":[{"type":"string","x-extensible-enum":["roughDraft","inProgress","readyForReview","verified"]},{"type":"null"}],"description":"Which default value this is, or null for a value a space admin added. Clients show the translated name of a default value unless `name` is set. New values can be added in later versions; handle unknown values."},"name":{"description":"Name set by a space admin, or null to show the default name.","type":["string","null"]},"color":{"type":"string","enum":["neutral","accent","info","success","warning","danger"],"description":"Color of the status: `neutral`, `accent`, `info`, `success`, `warning` or `danger`."},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Place in the list, starting at 0."},"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of pages with this status that the caller can view, without pages in the trash."}},"required":["id","builtIn","name","color","position","pages"],"additionalProperties":false,"description":"A status value of a space."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","builtIn":"verified","name":null,"color":"success","position":3,"pages":12}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidStatus`: The status is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidStatus":{"value":{"type":"urn:lunedo:problem:invalidStatus","title":"The status is not valid","status":400,"code":"invalidStatus"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `statusNotFound`: The status does not exist anymore.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"statusNotFound":{"value":{"type":"urn:lunedo:problem:statusNotFound","title":"The status does not exist anymore","status":404,"code":"statusNotFound"}}}}}},"409":{"description":"`statusExists`: A status with this name exists already.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"statusExists":{"value":{"type":"urn:lunedo:problem:statusExists","title":"A status with this name exists already","status":409,"code":"statusExists"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/page-statuses/order":{"put":{"operationId":"ownership.reorder","summary":"Reorder the page status values","description":"Sets the order in which editors see the values.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Ownership and status"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a status value."},"description":"Every status value of the space exactly once, in the new order."}},"required":["ids"],"additionalProperties":false,"description":"The new order."},"example":{"ids":["01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60"]}}}},"responses":{"200":{"description":"The values in their new order.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the status value."},"builtIn":{"anyOf":[{"type":"string","x-extensible-enum":["roughDraft","inProgress","readyForReview","verified"]},{"type":"null"}],"description":"Which default value this is, or null for a value a space admin added. Clients show the translated name of a default value unless `name` is set. New values can be added in later versions; handle unknown values."},"name":{"description":"Name set by a space admin, or null to show the default name.","type":["string","null"]},"color":{"type":"string","enum":["neutral","accent","info","success","warning","danger"],"description":"Color of the status: `neutral`, `accent`, `info`, `success`, `warning` or `danger`."},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Place in the list, starting at 0."},"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of pages with this status that the caller can view, without pages in the trash."}},"required":["id","builtIn","name","color","position","pages"],"additionalProperties":false,"description":"A status value of a space."},"description":"The values."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","builtIn":"verified","name":null,"color":"success","position":3,"pages":12}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidStatus`: The status is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidStatus":{"value":{"type":"urn:lunedo:problem:invalidStatus","title":"The status is not valid","status":400,"code":"invalidStatus"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/permissions":{"get":{"operationId":"spaces.permissions","summary":"List the permissions of a space","description":"Lists every holder with a role in the space: all internal users, all members, groups, then accounts.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The permissions.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the permission."},"principalKind":{"type":"string","enum":["account","group","organizationMembers","instanceUsers"],"description":"Holder of a role: an account (person or service account), a group, all members of the organization, or all internal users of the instance."},"principalId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the account or group, or null."},"name":{"description":"Name of the account or group, or null for the other holders.","type":["string","null"]},"email":{"description":"E-mail address of an account, or null.","type":["string","null"]},"organizationName":{"description":"Organization of a group, or null.","type":["string","null"]},"role":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."}},"required":["id","principalKind","principalId","name","email","organizationName","role"],"additionalProperties":false,"description":"A role of a holder in a space."},"description":"Permissions of the space."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a30","principalKind":"account","principalId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger","email":"anna@example.org","organizationName":null,"role":"admin"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"spaces.change","summary":"Change the permissions of a space","description":"Gives a holder a role, changes a role or removes one. A space always keeps at least one space admin, and nobody extends their own permissions. Every change is audited.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"action":{"type":"string","const":"grant","description":"Give a holder a role."},"principalKind":{"type":"string","enum":["account","group","organizationMembers","instanceUsers"],"description":"Holder of a role: an account (person or service account), a group, all members of the organization, or all internal users of the instance."},"principalId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the account or group; null for all members and all internal users."},"role":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."}},"required":["action","principalKind","principalId","role"],"additionalProperties":false,"description":"Give a role."},{"type":"object","properties":{"action":{"type":"string","const":"change","description":"Change the role of a holder."},"permissionId":{"type":"string","format":"uuid","description":"ID of the permission."},"role":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."}},"required":["action","permissionId","role"],"additionalProperties":false,"description":"Change a role."},{"type":"object","properties":{"action":{"type":"string","const":"remove","description":"Take the role of a holder away."},"permissionId":{"type":"string","format":"uuid","description":"ID of the permission."}},"required":["action","permissionId"],"additionalProperties":false,"description":"Remove a role."}],"description":"A change to the permissions of a space."},"example":{"action":"grant","principalKind":"account","principalId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","role":"reader"}}}},"responses":{"200":{"description":"The permissions after the change.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the permission."},"principalKind":{"type":"string","enum":["account","group","organizationMembers","instanceUsers"],"description":"Holder of a role: an account (person or service account), a group, all members of the organization, or all internal users of the instance."},"principalId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the account or group, or null."},"name":{"description":"Name of the account or group, or null for the other holders.","type":["string","null"]},"email":{"description":"E-mail address of an account, or null.","type":["string","null"]},"organizationName":{"description":"Organization of a group, or null.","type":["string","null"]},"role":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."}},"required":["id","principalKind","principalId","name","email","organizationName","role"],"additionalProperties":false,"description":"A role of a holder in a space."},"description":"Permissions of the space."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a30","principalKind":"account","principalId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger","email":"anna@example.org","organizationName":null,"role":"admin"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid. `portalAccountReaderOnly`: Portal accounts can only read.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"portalAccountReaderOnly":{"value":{"type":"urn:lunedo:problem:portalAccountReaderOnly","title":"Portal accounts can only read","status":400,"code":"portalAccountReaderOnly"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `selfExtension`: Nobody can extend their own permissions.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"selfExtension":{"value":{"type":"urn:lunedo:problem:selfExtension","title":"Nobody can extend their own permissions","status":403,"code":"selfExtension"}}}}}},"404":{"description":"`notFound`: Not found. `permissionNotFound`: The permission does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"permissionNotFound":{"value":{"type":"urn:lunedo:problem:permissionNotFound","title":"The permission does not exist","status":404,"code":"permissionNotFound"}}}}}},"409":{"description":"`alreadyGranted`: The holder already has a role in the space. `lastSpaceAdmin`: A space needs at least one space admin. `privateSpaceBroadGrant`: A private space gives roles to people and groups only.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"alreadyGranted":{"value":{"type":"urn:lunedo:problem:alreadyGranted","title":"The holder already has a role in the space","status":409,"code":"alreadyGranted"}},"lastSpaceAdmin":{"value":{"type":"urn:lunedo:problem:lastSpaceAdmin","title":"A space needs at least one space admin","status":409,"code":"lastSpaceAdmin"}},"privateSpaceBroadGrant":{"value":{"type":"urn:lunedo:problem:privateSpaceBroadGrant","title":"A private space gives roles to people and groups only","status":409,"code":"privateSpaceBroadGrant"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/permissions/{permissionId}":{"delete":{"operationId":"spaces.remove","summary":"Remove a permission","description":"Takes the role away from the holder. The last space admin cannot be removed.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"permissionId","in":"path","required":true,"description":"ID of the permission.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `permissionNotFound`: The permission does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"permissionNotFound":{"value":{"type":"urn:lunedo:problem:permissionNotFound","title":"The permission does not exist","status":404,"code":"permissionNotFound"}}}}}},"409":{"description":"`lastSpaceAdmin`: A space needs at least one space admin.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"lastSpaceAdmin":{"value":{"type":"urn:lunedo:problem:lastSpaceAdmin","title":"A space needs at least one space admin","status":409,"code":"lastSpaceAdmin"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/permissions/grants":{"post":{"operationId":"spaces.grant","summary":"Give several holders a role","description":"Gives all holders the same role in one change: either all get it or none. Nobody extends their own permissions, and every grant is audited.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"holders":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"object","properties":{"principalKind":{"type":"string","enum":["account","group","organizationMembers","instanceUsers"],"description":"Holder of a role: an account (person or service account), a group, all members of the organization, or all internal users of the instance."},"principalId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the account or group; null for all members and all internal users."}},"required":["principalKind","principalId"],"additionalProperties":false,"description":"A person, group or everyone of a kind."},"description":"Holders who get the role, up to 50."},"role":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."}},"required":["holders","role"],"additionalProperties":false,"description":"Several holders who get the same role."},"example":{"holders":[{"principalKind":"account","principalId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20"},{"principalKind":"group","principalId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a30"}],"role":"reader"}}}},"responses":{"200":{"description":"The permissions after the change.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the permission."},"principalKind":{"type":"string","enum":["account","group","organizationMembers","instanceUsers"],"description":"Holder of a role: an account (person or service account), a group, all members of the organization, or all internal users of the instance."},"principalId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the account or group, or null."},"name":{"description":"Name of the account or group, or null for the other holders.","type":["string","null"]},"email":{"description":"E-mail address of an account, or null.","type":["string","null"]},"organizationName":{"description":"Organization of a group, or null.","type":["string","null"]},"role":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."}},"required":["id","principalKind","principalId","name","email","organizationName","role"],"additionalProperties":false,"description":"A role of a holder in a space."},"description":"Permissions of the space."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a30","principalKind":"account","principalId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger","email":"anna@example.org","organizationName":null,"role":"admin"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid. `portalAccountReaderOnly`: Portal accounts can only read.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"portalAccountReaderOnly":{"value":{"type":"urn:lunedo:problem:portalAccountReaderOnly","title":"Portal accounts can only read","status":400,"code":"portalAccountReaderOnly"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `selfExtension`: Nobody can extend their own permissions.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"selfExtension":{"value":{"type":"urn:lunedo:problem:selfExtension","title":"Nobody can extend their own permissions","status":403,"code":"selfExtension"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`alreadyGranted`: The holder already has a role in the space. `privateSpaceBroadGrant`: A private space gives roles to people and groups only.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"alreadyGranted":{"value":{"type":"urn:lunedo:problem:alreadyGranted","title":"The holder already has a role in the space","status":409,"code":"alreadyGranted"}},"privateSpaceBroadGrant":{"value":{"type":"urn:lunedo:problem:privateSpaceBroadGrant","title":"A private space gives roles to people and groups only","status":409,"code":"privateSpaceBroadGrant"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/permissions/grants/preview":{"post":{"operationId":"spaces.previewGrants","summary":"Preview giving several holders a role","description":"Shows who would gain access if all holders got the role together. Nothing is changed.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"holders":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"object","properties":{"principalKind":{"type":"string","enum":["account","group","organizationMembers","instanceUsers"],"description":"Holder of a role: an account (person or service account), a group, all members of the organization, or all internal users of the instance."},"principalId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the account or group; null for all members and all internal users."}},"required":["principalKind","principalId"],"additionalProperties":false,"description":"A person, group or everyone of a kind."},"description":"Holders who get the role, up to 50."},"role":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."}},"required":["holders","role"],"additionalProperties":false,"description":"Several holders who get the same role."},"example":{"holders":[{"principalKind":"account","principalId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20"},{"principalKind":"group","principalId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a30"}],"role":"reader"}}}},"responses":{"200":{"description":"The change in access.","content":{"application/json":{"schema":{"type":"object","properties":{"gaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who get access."},"losing":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who lose access."},"raised":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role rises."},"lowered":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role drops."},"unlisted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of affected people the caller may not see; they are counted but not listed."},"truncated":{"type":"boolean","description":"Whether `changes` lists only the first 100 people."},"changes":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."},"before":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role before the change, or null for no access."},"after":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role after the change, or null for no access."}},"required":["accountId","name","before","after"],"additionalProperties":false,"description":"How the access of one person changes."},"description":"People whose access changes, ordered by name."}},"required":["gaining","losing","raised","lowered","unlisted","truncated","changes"],"additionalProperties":false,"description":"Who gains, loses or changes access."},"example":{"gaining":1,"losing":0,"raised":0,"lowered":0,"unlisted":0,"truncated":false,"changes":[{"accountId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger","before":null,"after":"reader"}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid. `portalAccountReaderOnly`: Portal accounts can only read.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"portalAccountReaderOnly":{"value":{"type":"urn:lunedo:problem:portalAccountReaderOnly","title":"Portal accounts can only read","status":400,"code":"portalAccountReaderOnly"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`alreadyGranted`: The holder already has a role in the space. `privateSpaceBroadGrant`: A private space gives roles to people and groups only.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"alreadyGranted":{"value":{"type":"urn:lunedo:problem:alreadyGranted","title":"The holder already has a role in the space","status":409,"code":"alreadyGranted"}},"privateSpaceBroadGrant":{"value":{"type":"urn:lunedo:problem:privateSpaceBroadGrant","title":"A private space gives roles to people and groups only","status":409,"code":"privateSpaceBroadGrant"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/permissions/preview":{"post":{"operationId":"spaces.preview","summary":"Preview a permission change","description":"Shows who would gain, lose or change access. Nothing is changed.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"action":{"type":"string","const":"grant","description":"Give a holder a role."},"principalKind":{"type":"string","enum":["account","group","organizationMembers","instanceUsers"],"description":"Holder of a role: an account (person or service account), a group, all members of the organization, or all internal users of the instance."},"principalId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"ID of the account or group; null for all members and all internal users."},"role":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."}},"required":["action","principalKind","principalId","role"],"additionalProperties":false,"description":"Give a role."},{"type":"object","properties":{"action":{"type":"string","const":"change","description":"Change the role of a holder."},"permissionId":{"type":"string","format":"uuid","description":"ID of the permission."},"role":{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."}},"required":["action","permissionId","role"],"additionalProperties":false,"description":"Change a role."},{"type":"object","properties":{"action":{"type":"string","const":"remove","description":"Take the role of a holder away."},"permissionId":{"type":"string","format":"uuid","description":"ID of the permission."}},"required":["action","permissionId"],"additionalProperties":false,"description":"Remove a role."}],"description":"A change to the permissions of a space."},"example":{"action":"grant","principalKind":"account","principalId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","role":"reader"}}}},"responses":{"200":{"description":"The change in access.","content":{"application/json":{"schema":{"type":"object","properties":{"gaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who get access."},"losing":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who lose access."},"raised":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role rises."},"lowered":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role drops."},"unlisted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of affected people the caller may not see; they are counted but not listed."},"truncated":{"type":"boolean","description":"Whether `changes` lists only the first 100 people."},"changes":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."},"before":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role before the change, or null for no access."},"after":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role after the change, or null for no access."}},"required":["accountId","name","before","after"],"additionalProperties":false,"description":"How the access of one person changes."},"description":"People whose access changes, ordered by name."}},"required":["gaining","losing","raised","lowered","unlisted","truncated","changes"],"additionalProperties":false,"description":"Who gains, loses or changes access."},"example":{"gaining":1,"losing":0,"raised":0,"lowered":0,"unlisted":0,"truncated":false,"changes":[{"accountId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger","before":null,"after":"reader"}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidHolder`: The holder cannot get a role in this space. `invalidInput`: The request is not valid. `portalAccountReaderOnly`: Portal accounts can only read.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidHolder":{"value":{"type":"urn:lunedo:problem:invalidHolder","title":"The holder cannot get a role in this space","status":400,"code":"invalidHolder"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"portalAccountReaderOnly":{"value":{"type":"urn:lunedo:problem:portalAccountReaderOnly","title":"Portal accounts can only read","status":400,"code":"portalAccountReaderOnly"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `permissionNotFound`: The permission does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"permissionNotFound":{"value":{"type":"urn:lunedo:problem:permissionNotFound","title":"The permission does not exist","status":404,"code":"permissionNotFound"}}}}}},"409":{"description":"`alreadyGranted`: The holder already has a role in the space. `privateSpaceBroadGrant`: A private space gives roles to people and groups only.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"alreadyGranted":{"value":{"type":"urn:lunedo:problem:alreadyGranted","title":"The holder already has a role in the space","status":409,"code":"alreadyGranted"}},"privateSpaceBroadGrant":{"value":{"type":"urn:lunedo:problem:privateSpaceBroadGrant","title":"A private space gives roles to people and groups only","status":409,"code":"privateSpaceBroadGrant"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/portal-accounts":{"get":{"operationId":"portalAccounts.list","summary":"List the portal accounts of a knowledge base","description":"Lists the portal accounts that read this knowledge base and the open invitations sent from it. Needs the permission to manage the organization's members.\n\nRequires the permission `space.portalAccounts.manage` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.portalAccounts.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Portal accounts and invitations.","content":{"application/json":{"schema":{"type":"object","properties":{"accounts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the reader."},"email":{"type":"string","description":"E-mail address the reader signs in with."},"state":{"type":"string","enum":["active","deactivated"],"description":"Whether the account can sign in."},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the access ends, or null. ISO 8601 timestamp in UTC."},"createdAt":{"type":"string","format":"date-time","description":"When the account was created. ISO 8601 timestamp in UTC."},"lastSignInAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the reader last signed in, or null. ISO 8601 timestamp in UTC."},"otherOrganizations":{"type":"boolean","description":"Whether the account also reads knowledge bases of other organizations."}},"required":["id","name","email","state","expiresAt","createdAt","lastSignInAt","otherOrganizations"],"additionalProperties":false,"description":"A portal account."},"description":"Portal accounts that read this knowledge base."},"invitations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the invitation."},"email":{"type":"string","description":"Invited address."},"membershipExpiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the access will end, or null. ISO 8601 timestamp in UTC."},"expiresAt":{"type":"string","format":"date-time","description":"When the invitation link expires. ISO 8601 timestamp in UTC."},"invitedByName":{"description":"Who sent the invitation.","type":["string","null"]}},"required":["id","email","membershipExpiresAt","expiresAt","invitedByName"],"additionalProperties":false,"description":"An open invitation."},"description":"Open invitations sent from this knowledge base."}},"required":["accounts","invitations"],"additionalProperties":false,"description":"Readers with portal accounts."},"example":{"accounts":[],"invitations":[]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notKnowledgeBase`: The space is not a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"portalAccounts.invite","summary":"Invite a reader as a portal account","description":"Sends an invitation to read the knowledge base. The reader creates a portal account that reads only the knowledge bases it was invited to. Open member invitations for the same address stay valid. The person who invites is responsible for the account. Needs the permission to manage the organization's members. Audited.\n\nRequires the permission `space.portalAccounts.manage` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.portalAccounts.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","maxLength":254,"format":"email","description":"E-mail address of the reader."},"expiresAt":{"description":"When the access ends, or null for no end.","anyOf":[{"description":"When the access ends. ISO 8601 timestamp; an offset is allowed.","type":"string","format":"date-time"},{"type":"null"}]}},"required":["email"],"additionalProperties":false,"description":"The invitation."},"example":{"email":"reader@example.org","expiresAt":"2027-03-31T00:00:00.000Z"}}}},"responses":{"201":{"description":"The invitation.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the invitation."},"email":{"type":"string","description":"Invited address."},"membershipExpiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the access will end, or null. ISO 8601 timestamp in UTC."},"expiresAt":{"type":"string","format":"date-time","description":"When the invitation link expires. ISO 8601 timestamp in UTC."}},"required":["id","email","membershipExpiresAt","expiresAt"],"additionalProperties":false,"description":"The new invitation."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","email":"reader@example.org","membershipExpiresAt":"2027-03-31T00:00:00.000Z","expiresAt":"2026-10-27T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `expiryInPast`: The expiry lies in the past. `invalidInput`: The request is not valid. `invalidResponsible`: The responsible person is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"expiryInPast":{"value":{"type":"urn:lunedo:problem:expiryInPast","title":"The expiry lies in the past","status":400,"code":"expiryInPast"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidResponsible":{"value":{"type":"urn:lunedo:problem:invalidResponsible","title":"The responsible person is not valid","status":400,"code":"invalidResponsible"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notKnowledgeBase`: The space is not a knowledge base. `portalAudienceRequired`: The knowledge base is not for portal accounts.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}},"portalAudienceRequired":{"value":{"type":"urn:lunedo:problem:portalAudienceRequired","title":"The knowledge base is not for portal accounts","status":409,"code":"portalAudienceRequired"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/portal-accounts/{accountId}":{"delete":{"operationId":"portalAccounts.remove","summary":"Remove a portal account from the organization","description":"The account no longer reads the organization's knowledge bases. It keeps reading other organizations it belongs to. Audited.\n\nRequires the permission `space.portalAccounts.manage` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.portalAccounts.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}},{"name":"accountId","in":"path","required":true,"description":"ID of the portal account.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `portalAccountNotFound`: The portal account does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"portalAccountNotFound":{"value":{"type":"urn:lunedo:problem:portalAccountNotFound","title":"The portal account does not exist","status":404,"code":"portalAccountNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/portal-accounts/{accountId}/deactivate":{"post":{"operationId":"portalAccounts.deactivate","summary":"Deactivate a portal account","description":"Ends all sessions of the account; it can no longer sign in. Its ratings and notes stay anonymous as before. Only for accounts that read no other organization. Audited.\n\nRequires the permission `space.portalAccounts.manage` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.portalAccounts.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}},{"name":"accountId","in":"path","required":true,"description":"ID of the portal account.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `portalAccountNotFound`: The portal account does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"portalAccountNotFound":{"value":{"type":"urn:lunedo:problem:portalAccountNotFound","title":"The portal account does not exist","status":404,"code":"portalAccountNotFound"}}}}}},"409":{"description":"`portalAccountShared`: The portal account belongs to other organizations too.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"portalAccountShared":{"value":{"type":"urn:lunedo:problem:portalAccountShared","title":"The portal account belongs to other organizations too","status":409,"code":"portalAccountShared"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/portal-invitations/{invitationId}":{"delete":{"operationId":"portalAccounts.revoke","summary":"Withdraw an invitation of a portal account","description":"The link in the invitation stops working. Audited.\n\nRequires the permission `space.portalAccounts.manage` on the space in `spaceId`.","tags":["Knowledge bases"],"x-lunedo-permission":{"action":"space.portalAccounts.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}},{"name":"invitationId","in":"path","required":true,"description":"ID of the invitation.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`invitationNotFound`: The invitation does not exist. `notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invitationNotFound":{"value":{"type":"urn:lunedo:problem:invitationNotFound","title":"The invitation does not exist","status":404,"code":"invitationNotFound"}},"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/restricted-pages":{"get":{"operationId":"pageAccess.restrictedPages","summary":"List the restricted pages of a space","description":"Lists every restricted page of the space with its title, for space admins. Their content stays hidden; admins can only remove restrictions.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Page access"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Restricted pages, ordered by title.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"ID of the page."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the page in the addresses of the app."},"title":{"type":"string","description":"Title of the page."},"kind":{"type":"string","description":"Kind of the item."},"view":{"anyOf":[{"type":"object","properties":{"setBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who set it."},"setAt":{"type":"string","format":"date-time","description":"When it was set. ISO 8601 timestamp in UTC."}},"required":["setBy","setAt"],"additionalProperties":false,"description":"A restriction of the page itself."},{"type":"null"}],"description":"The view restriction, if any."},"edit":{"anyOf":[{"type":"object","properties":{"setBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name, or null when hidden.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who set it."},"setAt":{"type":"string","format":"date-time","description":"When it was set. ISO 8601 timestamp in UTC."}},"required":["setBy","setAt"],"additionalProperties":false,"description":"A restriction of the page itself."},{"type":"null"}],"description":"The edit restriction, if any."},"orphaned":{"type":"boolean","description":"Whether nobody on the access list has an active account anymore."}},"required":["itemId","number","title","kind","view","edit","orphaned"],"additionalProperties":false,"description":"A restricted page, listed for space admins without its content."},"description":"Restricted pages."},"example":[{"itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","number":1077,"title":"Salaries 2027","kind":"page","view":{"setBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a21","name":"Lukas Hofer"},"setAt":"2026-10-01T09:30:00.000Z"},"edit":null,"orphaned":false}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/restricted-pages/{itemId}/restrictions/{kind}":{"delete":{"operationId":"pageAccess.removeRestriction","summary":"Remove a restriction as space admin","description":"Removes a restriction of a page without reading it. The page becomes visible to everyone with access to the space; the removal is written to the audit log.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Page access"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"itemId","in":"path","required":true,"description":"ID of the restricted page.","schema":{"type":"string","format":"uuid"}},{"name":"kind","in":"path","required":true,"description":"`view` or `edit`.","schema":{"type":"string","enum":["view","edit"]}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `restrictionNotFound`: The page is not restricted.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"restrictionNotFound":{"value":{"type":"urn:lunedo:problem:restrictionNotFound","title":"The page is not restricted","status":404,"code":"restrictionNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/reviews":{"get":{"operationId":"reviews.list","summary":"List the articles to review","description":"Lists articles that are overdue, due within 30 days, whose source page changed or that have no active owner. Only articles the caller may edit are listed.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Knowledge base reviews"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}},{"name":"filter","in":"query","required":false,"description":"`due`: overdue or with a changed source page. `soon`: due within 30 days. `unowned`: without an active owner. `translations`: translations whose original was published after them. `all`: every article of these four.","schema":{"default":"all","type":"string","enum":["all","due","soon","unowned","translations"]}},{"name":"mine","in":"query","required":false,"description":"Only articles the caller owns.","schema":{"default":"false","type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"The articles.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the article."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the article in the addresses of the app."},"title":{"type":"string","description":"Title of the article."},"type":{"anyOf":[{"type":"string","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values."},"categoryPath":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the category."},"title":{"type":"string","description":"Title."}},"required":["id","title"],"additionalProperties":false,"description":"A category."},"description":"Folders above the article that the caller can read, top level first."},"owner":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the person."},"name":{"description":"Name of the person, or null when the caller may not see the person.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null without one. Changes whenever the picture changes; load the picture from `GET /api/v1/accounts/{accountId}/picture`.","type":["string","null"]}},"required":["id","name","pictureRef"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"The owner, or null when the article has no active owner."},"ownerActive":{"type":"boolean","description":"Whether the article has an active owner."},"formerOwner":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the person."},"name":{"description":"Name of the person, or null when the caller may not see the person.","type":["string","null"]},"pictureRef":{"description":"Version of the profile picture, or null without one. Changes whenever the picture changes; load the picture from `GET /api/v1/accounts/{accountId}/picture`.","type":["string","null"]}},"required":["id","name","pictureRef"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"The owner who left, or null when the owner is active or the article never had one."},"intervalMonths":{"anyOf":[{"anyOf":[{"type":"number","const":3},{"type":"number","const":6},{"type":"number","const":12}],"description":"Review interval in months."},{"type":"null"}],"description":"Interval that applies, or null."},"inherited":{"type":"boolean","description":"Whether the interval comes from the knowledge base."},"publishedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the article was first published, or null. ISO 8601 timestamp in UTC."},"reviewedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When it was last reviewed, or null. ISO 8601 timestamp in UTC."},"dueAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the review is due, or null. ISO 8601 timestamp in UTC."},"sourceChangedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When a source page changed after the last review, or null. ISO 8601 timestamp in UTC."},"state":{"type":"string","enum":["overdue","sourceChanged","dueSoon","current","off"],"description":"`overdue`: the interval has passed. `sourceChanged`: a source page changed since the last review. `dueSoon`: due within 30 days. `current`: reviewed within the interval. `off`: no interval applies."},"language":{"description":"Language of a translation, or null for an article in the default language.","type":["string","null"]},"translationOutdated":{"type":"boolean","description":"Whether this is a translation and its original was published after it."}},"required":["id","number","title","type","categoryPath","owner","ownerActive","formerOwner","intervalMonths","inherited","publishedAt","reviewedAt","dueAt","sourceChangedAt","state","language","translationOutdated"],"additionalProperties":false,"description":"An article that needs a review, an owner or an updated translation."},"description":"Due and overdue articles first, then articles due soon."},"nextCursor":{"description":"Cursor for the next page, or null on the last page.","type":["string","null"]},"counts":{"type":"object","properties":{"all":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Articles in the list."},"due":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Overdue articles and articles with a changed source page."},"soon":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Articles due within 30 days."},"unowned":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Articles without an active owner."},"translations":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Translations whose original was published after them."}},"required":["all","due","soon","unowned","translations"],"additionalProperties":false,"description":"Number of articles per filter, with the `mine` choice applied."}},"required":["items","nextCursor","counts"],"additionalProperties":false,"description":"Articles to review that the caller may edit."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a50","number":4711,"title":"Set up the VPN at home","type":"howTo","categoryPath":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","title":"IT"}],"owner":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Weber","pictureRef":null},"ownerActive":true,"formerOwner":null,"intervalMonths":6,"inherited":true,"publishedAt":"2026-03-02T09:00:00.000Z","reviewedAt":"2026-04-02T09:00:00.000Z","dueAt":"2026-10-02T09:00:00.000Z","sourceChangedAt":null,"state":"overdue","language":null,"translationOutdated":false}],"nextCursor":null,"counts":{"all":1,"due":1,"soon":0,"unowned":0,"translations":0}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notKnowledgeBase`: The space is not a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/settings":{"get":{"operationId":"templates.spaceSettings","summary":"List the settings of a space","description":"Lists the settings that can be set for the space: default editing mode of new pages, the idle time after which live pages get a version, the trash periods, reactions, page status, whether export is allowed and the content language search uses. Each shows whether it is inherited or set here.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Settings"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Settings of the space.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Schema113ae44d8375"},"description":"Settings, with their effective values and levels."},"example":[]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/settings/{key}":{"put":{"operationId":"templates.updateSpaceSetting","summary":"Change a setting of a space","description":"Sets or clears a setting for the space. Trash periods cannot go below the minimum the instance sets; a setting locked above cannot change.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Settings"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"key","in":"path","required":true,"description":"Key of the setting.","schema":{"type":"string","maxLength":100}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"value":{"description":"New value. Its type depends on the setting.","$ref":"#/components/schemas/Schema113ae44d8375"},"clear":{"description":"Remove the value at this level, so the level above applies.","type":"boolean","const":true},"locked":{"description":"Lock or unlock the setting for the levels below.","type":"boolean"}},"additionalProperties":false,"description":"A change to a setting. Send at least one field."},"example":{"value":"live"}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidSetting`: The setting value is not valid. `settingAboveMaximum`: The value is above the maximum set for the instance. `settingBelowMinimum`: The value is below the minimum set for the instance.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidSetting":{"value":{"type":"urn:lunedo:problem:invalidSetting","title":"The setting value is not valid","status":400,"code":"invalidSetting"}},"settingAboveMaximum":{"value":{"type":"urn:lunedo:problem:settingAboveMaximum","title":"The value is above the maximum set for the instance","status":400,"code":"settingAboveMaximum"}},"settingBelowMinimum":{"value":{"type":"urn:lunedo:problem:settingBelowMinimum","title":"The value is below the minimum set for the instance","status":400,"code":"settingBelowMinimum"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`settingLocked`: A higher level locked the setting. `settingNotAtLevel`: The setting cannot be set at this level.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"settingLocked":{"value":{"type":"urn:lunedo:problem:settingLocked","title":"A higher level locked the setting","status":409,"code":"settingLocked"}},"settingNotAtLevel":{"value":{"type":"urn:lunedo:problem:settingNotAtLevel","title":"The setting cannot be set at this level","status":409,"code":"settingNotAtLevel"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/shortcuts":{"get":{"operationId":"shortcuts.list","summary":"List the shortcuts of a space","description":"Lists the shortcuts in the space sidebar. Shortcuts to content the caller cannot open are left out entirely.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The shortcuts.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the shortcut."},"label":{"type":"string","description":"The label shown in the sidebar."},"url":{"description":"The external address, or null for content in Lunedo.","type":["string","null"]},"item":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the content."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the content in the addresses of the app."},"kind":{"type":"string","description":"Kind of the content. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title of the content."},"spaceKey":{"type":"string","description":"Key of the space the content is in."}},"required":["id","number","kind","title","spaceKey"],"additionalProperties":false},{"type":"null"}],"description":"The content in Lunedo, or null for an external address or content the caller cannot open."},"hidden":{"type":"boolean","description":"Whether the caller cannot open the content. Only space admins see such shortcuts, in the settings."},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Position in the list."}},"required":["id","label","url","item","hidden","position"],"additionalProperties":false,"description":"A shortcut in the space sidebar."},"description":"The shortcuts, in order."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a50","label":"On-call rota","url":null,"item":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a51","number":1051,"kind":"page","title":"On-call rota 2026","spaceKey":"OPS"},"hidden":false,"position":0}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"shortcuts.add","summary":"Add a shortcut","description":"Adds a shortcut at the end of the list. A space can have up to 20 shortcuts. Content needs to be open to you; people who cannot open it do not see the shortcut.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","maxLength":80,"description":"Up to 80 characters."},"target":{"anyOf":[{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"A page, folder, blog post or meeting series you can open."}},"required":["itemId"],"additionalProperties":false},{"type":"object","properties":{"url":{"type":"string","maxLength":2000,"description":"An address starting with https:// or http://."}},"required":["url"],"additionalProperties":false}],"description":"Where the shortcut leads."}},"required":["label","target"],"additionalProperties":false,"description":"The new shortcut."},"example":{"label":"Status page","target":{"url":"https://status.example.org"}}}}},"responses":{"201":{"description":"The new shortcut.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the shortcut."},"label":{"type":"string","description":"The label shown in the sidebar."},"url":{"description":"The external address, or null for content in Lunedo.","type":["string","null"]},"item":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the content."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the content in the addresses of the app."},"kind":{"type":"string","description":"Kind of the content. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title of the content."},"spaceKey":{"type":"string","description":"Key of the space the content is in."}},"required":["id","number","kind","title","spaceKey"],"additionalProperties":false},{"type":"null"}],"description":"The content in Lunedo, or null for an external address or content the caller cannot open."},"hidden":{"type":"boolean","description":"Whether the caller cannot open the content. Only space admins see such shortcuts, in the settings."},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Position in the list."}},"required":["id","label","url","item","hidden","position"],"additionalProperties":false,"description":"A shortcut in the space sidebar."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a50","label":"On-call rota","url":null,"item":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a51","number":1051,"kind":"page","title":"On-call rota 2026","spaceKey":"OPS"},"hidden":false,"position":0}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidShortcut`: The shortcut is not valid. `shortcutTargetNotFound`: The content of the shortcut cannot be found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidShortcut":{"value":{"type":"urn:lunedo:problem:invalidShortcut","title":"The shortcut is not valid","status":400,"code":"invalidShortcut"}},"shortcutTargetNotFound":{"value":{"type":"urn:lunedo:problem:shortcutTargetNotFound","title":"The content of the shortcut cannot be found","status":400,"code":"shortcutTargetNotFound"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`tooManyShortcuts`: The space has too many shortcuts.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"tooManyShortcuts":{"value":{"type":"urn:lunedo:problem:tooManyShortcuts","title":"The space has too many shortcuts","status":409,"code":"tooManyShortcuts"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/shortcuts/{shortcutId}":{"delete":{"operationId":"shortcuts.remove","summary":"Remove a shortcut","description":"Removes the shortcut from the sidebar of the space.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"shortcutId","in":"path","required":true,"description":"ID of the shortcut.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `shortcutNotFound`: The shortcut does not exist anymore.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"shortcutNotFound":{"value":{"type":"urn:lunedo:problem:shortcutNotFound","title":"The shortcut does not exist anymore","status":404,"code":"shortcutNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"patch":{"operationId":"shortcuts.update","summary":"Change a shortcut","description":"Changes the label or the target. A new content target needs to be open to the caller.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"shortcutId","in":"path","required":true,"description":"ID of the shortcut.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","maxLength":80,"description":"Up to 80 characters."},"target":{"anyOf":[{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"A page, folder, blog post or meeting series you can open."}},"required":["itemId"],"additionalProperties":false},{"type":"object","properties":{"url":{"type":"string","maxLength":2000,"description":"An address starting with https:// or http://."}},"required":["url"],"additionalProperties":false}],"description":"Where the shortcut leads."}},"additionalProperties":false,"description":"The changes."},"example":{"label":"On-call"}}}},"responses":{"200":{"description":"The changed shortcut.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the shortcut."},"label":{"type":"string","description":"The label shown in the sidebar."},"url":{"description":"The external address, or null for content in Lunedo.","type":["string","null"]},"item":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the content."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the content in the addresses of the app."},"kind":{"type":"string","description":"Kind of the content. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title of the content."},"spaceKey":{"type":"string","description":"Key of the space the content is in."}},"required":["id","number","kind","title","spaceKey"],"additionalProperties":false},{"type":"null"}],"description":"The content in Lunedo, or null for an external address or content the caller cannot open."},"hidden":{"type":"boolean","description":"Whether the caller cannot open the content. Only space admins see such shortcuts, in the settings."},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Position in the list."}},"required":["id","label","url","item","hidden","position"],"additionalProperties":false,"description":"A shortcut in the space sidebar."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a50","label":"On-call rota","url":null,"item":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a51","number":1051,"kind":"page","title":"On-call rota 2026","spaceKey":"OPS"},"hidden":false,"position":0}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidShortcut`: The shortcut is not valid. `shortcutTargetNotFound`: The content of the shortcut cannot be found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidShortcut":{"value":{"type":"urn:lunedo:problem:invalidShortcut","title":"The shortcut is not valid","status":400,"code":"invalidShortcut"}},"shortcutTargetNotFound":{"value":{"type":"urn:lunedo:problem:shortcutTargetNotFound","title":"The content of the shortcut cannot be found","status":400,"code":"shortcutTargetNotFound"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `shortcutNotFound`: The shortcut does not exist anymore.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"shortcutNotFound":{"value":{"type":"urn:lunedo:problem:shortcutNotFound","title":"The shortcut does not exist anymore","status":404,"code":"shortcutNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/shortcuts/manage":{"get":{"operationId":"shortcuts.manage","summary":"List all shortcuts of a space for editing","description":"Lists every shortcut, also those to content the caller cannot open. For those, `hidden` is true and the content is not named.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The shortcuts.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the shortcut."},"label":{"type":"string","description":"The label shown in the sidebar."},"url":{"description":"The external address, or null for content in Lunedo.","type":["string","null"]},"item":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the content."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the content in the addresses of the app."},"kind":{"type":"string","description":"Kind of the content. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title of the content."},"spaceKey":{"type":"string","description":"Key of the space the content is in."}},"required":["id","number","kind","title","spaceKey"],"additionalProperties":false},{"type":"null"}],"description":"The content in Lunedo, or null for an external address or content the caller cannot open."},"hidden":{"type":"boolean","description":"Whether the caller cannot open the content. Only space admins see such shortcuts, in the settings."},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Position in the list."}},"required":["id","label","url","item","hidden","position"],"additionalProperties":false,"description":"A shortcut in the space sidebar."},"description":"The shortcuts, in order."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a50","label":"On-call rota","url":null,"item":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a51","number":1051,"kind":"page","title":"On-call rota 2026","spaceKey":"OPS"},"hidden":false,"position":0}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/shortcuts/order":{"put":{"operationId":"shortcuts.reorder","summary":"Reorder the shortcuts","description":"Sets the order of the shortcuts in the sidebar. Name every shortcut of the space once.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"maxItems":20,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a shortcut."},"description":"Every shortcut, in the new order."}},"required":["ids"],"additionalProperties":false,"description":"The new order."},"example":{"ids":["01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a50"]}}}},"responses":{"200":{"description":"The shortcuts in their new order.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the shortcut."},"label":{"type":"string","description":"The label shown in the sidebar."},"url":{"description":"The external address, or null for content in Lunedo.","type":["string","null"]},"item":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the content."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the content in the addresses of the app."},"kind":{"type":"string","description":"Kind of the content. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title of the content."},"spaceKey":{"type":"string","description":"Key of the space the content is in."}},"required":["id","number","kind","title","spaceKey"],"additionalProperties":false},{"type":"null"}],"description":"The content in Lunedo, or null for an external address or content the caller cannot open."},"hidden":{"type":"boolean","description":"Whether the caller cannot open the content. Only space admins see such shortcuts, in the settings."},"position":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Position in the list."}},"required":["id","label","url","item","hidden","position"],"additionalProperties":false,"description":"A shortcut in the space sidebar."},"description":"The shortcuts, in order."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a50","label":"On-call rota","url":null,"item":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a51","number":1051,"kind":"page","title":"On-call rota 2026","spaceKey":"OPS"},"hidden":false,"position":0}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidShortcut`: The shortcut is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidShortcut":{"value":{"type":"urn:lunedo:problem:invalidShortcut","title":"The shortcut is not valid","status":400,"code":"invalidShortcut"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/statistics":{"get":{"operationId":"statistics.overview","summary":"Get the reader statistics of a knowledge base","description":"Returns searches, terms, ratings and views in the portal for a period. For editors and admins of the knowledge base.\n\nRequires the permission `space.edit` on the space in `spaceId`.","tags":["Knowledge base statistics"],"x-lunedo-permission":{"action":"space.edit","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}},{"name":"period","in":"query","required":false,"description":"`7d`, `30d` or `90d` for the last 7, 30 or 90 days, `12m` for the last 12 months, each up to today.","schema":{"default":"30d","type":"string","enum":["7d","30d","90d","12m"]}}],"responses":{"200":{"description":"The statistics.","content":{"application/json":{"schema":{"type":"object","properties":{"period":{"type":"object","properties":{"from":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$","description":"First day, UTC."},"to":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$","description":"Last day, UTC."}},"required":["from","to"],"additionalProperties":false,"description":"The days counted, both included."},"searches":{"type":"object","properties":{"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Searches in the portal."},"zeroResults":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Searches without results."}},"required":["total","zeroResults"],"additionalProperties":false,"description":"Searches in the period."},"ratings":{"type":"object","properties":{"helpful":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Answers “yes” to “Was this helpful?”."},"unhelpful":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Answers “no”."}},"required":["helpful","unhelpful"],"additionalProperties":false,"description":"Ratings of the articles the caller can read."},"views":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Views of the articles the caller can read."},"topTerms":{"type":"array","items":{"type":"object","properties":{"term":{"type":"string","description":"The search term, trimmed and in lowercase."},"searches":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Searches for the term in the period."},"zeroResults":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Of these, searches without results."},"lastSearchedAt":{"type":"string","format":"date-time","description":"Hour of the last search for the term. ISO 8601 timestamp in UTC."}},"required":["term","searches","zeroResults","lastSearchedAt"],"additionalProperties":false,"description":"A search term."},"description":"Up to 20 most frequent terms, each searched at least 3 times."},"zeroResultTerms":{"type":"array","items":{"type":"object","properties":{"term":{"type":"string","description":"The search term, trimmed and in lowercase."},"searches":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Searches for the term in the period."},"zeroResults":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Of these, searches without results."},"lastSearchedAt":{"type":"string","format":"date-time","description":"Hour of the last search for the term. ISO 8601 timestamp in UTC."}},"required":["term","searches","zeroResults","lastSearchedAt"],"additionalProperties":false,"description":"A search term."},"description":"Up to 20 terms most often searched without results, each at least 3 times."},"unhelpful":{"type":"array","items":{"type":"object","properties":{"article":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the article."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the article in the addresses of the app."},"title":{"type":"string","description":"Title of the article."},"categoryPath":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the category."},"title":{"type":"string","description":"Title."}},"required":["id","title"],"additionalProperties":false,"description":"A category."},"description":"Folders above the article that the caller can read, top level first."}},"required":["id","number","title","categoryPath"],"additionalProperties":false,"description":"An article the caller can read."},"helpful":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Answers “yes”."},"unhelpful":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Answers “no”."},"feedback":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Notes on what was missing, still kept."}},"required":["article","helpful","unhelpful","feedback"],"additionalProperties":false,"description":"An article rated as not helpful."},"description":"Up to 10 articles with the most answers “no”."},"mostRead":{"type":"array","items":{"type":"object","properties":{"article":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the article."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the article in the addresses of the app."},"title":{"type":"string","description":"Title of the article."},"categoryPath":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the category."},"title":{"type":"string","description":"Title."}},"required":["id","title"],"additionalProperties":false,"description":"A category."},"description":"Folders above the article that the caller can read, top level first."}},"required":["id","number","title","categoryPath"],"additionalProperties":false,"description":"An article the caller can read."},"views":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Views in the period."}},"required":["article","views"],"additionalProperties":false,"description":"A read article."},"description":"Up to 10 articles with the most views."}},"required":["period","searches","ratings","views","topTerms","zeroResultTerms","unhelpful","mostRead"],"additionalProperties":false,"description":"What readers searched and how they rated articles in the portal. Nothing refers to a person; articles the caller cannot read are left out."},"example":{"period":{"from":"2026-09-20","to":"2026-10-19"},"searches":{"total":4812,"zeroResults":308},"ratings":{"helpful":1047,"unhelpful":157},"views":9310,"topTerms":[{"term":"vpn","searches":412,"zeroResults":0,"lastSearchedAt":"2026-10-19T08:00:00.000Z"}],"zeroResultTerms":[{"term":"parking permit","searches":37,"zeroResults":37,"lastSearchedAt":"2026-10-18T14:00:00.000Z"}],"unhelpful":[{"article":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a50","number":4711,"title":"Set up the VPN at home","categoryPath":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","title":"IT"}]},"helpful":23,"unhelpful":18,"feedback":3}],"mostRead":[{"article":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a50","number":4711,"title":"Set up the VPN at home","categoryPath":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","title":"IT"}]},"views":640}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notKnowledgeBase`: The space is not a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/statistics/articles/{itemId}/feedback":{"get":{"operationId":"statistics.feedback","summary":"List the notes on an article","description":"Lists what readers wrote after answering “no” to “Was this helpful?” in the period. Notes are deleted when the retention of the knowledge base ends.\n\nRequires the permission `space.edit` on the space in `spaceId`.","tags":["Knowledge base statistics"],"x-lunedo-permission":{"action":"space.edit","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}},{"name":"itemId","in":"path","required":true,"description":"ID of the article.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from `nextCursor` of the previous page. Leave it out for the first page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items in the page, from 1 to 200. Default 50.","schema":{"default":50,"type":"integer","minimum":1,"maximum":200}},{"name":"period","in":"query","required":false,"description":"`7d`, `30d` or `90d` for the last 7, 30 or 90 days, `12m` for the last 12 months, each up to today.","schema":{"default":"30d","type":"string","enum":["7d","30d","90d","12m"]}}],"responses":{"200":{"description":"The notes.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the note."},"itemId":{"type":"string","format":"uuid","description":"ID of the article."},"day":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$","description":"Day the note was written, UTC."},"text":{"type":"string","description":"What the reader wrote, without any reference to them."}},"required":["id","itemId","day","text"],"additionalProperties":false,"description":"A note on what was missing."},"description":"Notes, newest first."},"nextCursor":{"description":"Cursor for the next page, or null on the last page.","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false,"description":"Notes readers left after answering “no”."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a80","itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a50","day":"2026-10-17","text":"Step 2 looks different on my laptop."}],"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notKnowledgeBase`: The space is not a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/statistics/feedback/{feedbackId}":{"delete":{"operationId":"statistics.deleteFeedback","summary":"Delete a note","description":"Deletes a note for good, for example when it contains personal data. Only space admins. Audited without the text.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Knowledge base statistics"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the knowledge base.","schema":{"type":"string","format":"uuid"}},{"name":"feedbackId","in":"path","required":true,"description":"ID of the note.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`feedbackNotFound`: The note does not exist. `notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"feedbackNotFound":{"value":{"type":"urn:lunedo:problem:feedbackNotFound","title":"The note does not exist","status":404,"code":"feedbackNotFound"}},"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`notKnowledgeBase`: The space is not a knowledge base.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notKnowledgeBase":{"value":{"type":"urn:lunedo:problem:notKnowledgeBase","title":"The space is not a knowledge base","status":409,"code":"notKnowledgeBase"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/storage":{"get":{"operationId":"accessRequests.spaceStorage","summary":"Get the storage used by a space","description":"Sums the attachments of the space, with every stored version.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Access"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The storage.","content":{"application/json":{"schema":{"type":"object","properties":{"bytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Bytes used by all versions of all attachments."},"files":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of stored files."}},"required":["bytes","files"],"additionalProperties":false,"description":"Storage used by attachments."},"example":{"bytes":104857600,"files":42}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/template-gallery":{"get":{"operationId":"templates.gallery","summary":"List the templates for new pages","description":"Lists every template the caller can use in the space: the built-in templates in the caller's language, then those of the instance, the organization and the space.\n\nRequires the permission `space.edit` on the space in `spaceId`.","tags":["Templates"],"x-lunedo-permission":{"action":"space.edit","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"q","in":"query","required":false,"description":"Text the name or description contains.","schema":{"default":"","type":"string","maxLength":100}}],"responses":{"200":{"description":"Templates.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"ID of the template. Built-in templates have IDs starting with `builtin:`."},"level":{"type":"string","enum":["builtIn","instance","organization","space"],"description":"Where the template comes from: built in, or from the instance, the organization or the space."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization of an organization template, or null."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space of a space template, or null."},"name":{"type":"string","description":"Name."},"description":{"type":"string","description":"Short description."},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","description":"Title of new pages; `{key}` inserts the value of an input field."},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","description":"How often. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"Weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"Default rhythm."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Default duration in minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false,"description":"Defaults of a series template."},{"type":"null"}],"description":"For a series template: defaults for rhythm and duration of new meeting series; otherwise null."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Article type of articles created from a template of a knowledge base, or null."},"updatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the template last changed, or null for built-in templates. ISO 8601 timestamp in UTC."}},"required":["id","level","organizationId","spaceId","name","description","category","title","fields","document","series","articleType","updatedAt"],"additionalProperties":false,"description":"A page template."},"description":"Templates."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","level":"space","organizationId":null,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","name":"Change request","description":"Planned change with risk and rollback","category":"operations","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"series":null,"articleType":null,"updatedAt":"2026-10-05T08:00:00.000Z"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/template-imports":{"post":{"operationId":"templateFiles.spaceImport","summary":"Upload a template file for import","description":"Checks a template file and returns a preview; nothing is saved yet. Send the file with `Content-Type: application/octet-stream`, at most 20 MB, with at most 50 templates and 200 files. Every part is validated like content entered in the editor. Confirm the preview to import.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Templates"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"name","in":"query","required":true,"description":"Name of the uploaded file. Paths and control characters are removed.","schema":{"type":"string","minLength":1,"maxLength":1020}}],"requestBody":{"required":true,"description":"The template file.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"201":{"description":"The preview.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the preview; confirm or discard it with this ID."},"fileName":{"type":"string","description":"Name of the uploaded file."},"templates":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Position in the file, counted from 0."},"name":{"type":"string","description":"Name of the template, or `#n` when the file gives none."},"description":{"type":"string","description":"Short description."},"category":{"anyOf":[{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"]},{"type":"null"}],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"language":{"anyOf":[{"type":"string","enum":["en","de"]},{"type":"null"}],"description":"Language the file states, or null."},"title":{"type":"string","description":"Title pattern of new pages."},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Input fields."},"series":{"anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","description":"How often. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"Weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"Default rhythm."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Default duration in minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false,"description":"Defaults of a series template."},{"type":"null"}],"description":"Series defaults, or null."},"document":{"anyOf":[{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},{"type":"null"}],"description":"Content as it will be saved, or null if it is not valid."},"files":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the file; the preview content refers to it."},"name":{"type":"string","description":"File name."},"mediaType":{"type":"string","description":"Media type."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size in bytes after the safety checks."}},"required":["id","name","mediaType","size"],"additionalProperties":false,"description":"A file of the template."},"description":"Files the content uses."},"removed":{"type":"object","propertyNames":{"type":"string","enum":["pageLink","mention","include","diagramReference","whiteboard","templateButton","report","roadmap","person","comment","meetingTopic","file","unsupportedMacro"]},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"What is removed because it cannot work in another instance, by kind: `pageLink` (links to pages and spaces), `mention`, `include`, `diagramReference`, `whiteboard`, `templateButton`, `report`, `roadmap`, `person`, `comment`, `meetingTopic`, `file` (files that are not part of the template or not images) and `unsupportedMacro`."},"blockedEmbeds":{"type":"array","items":{"type":"string","description":"Address of an embed."},"description":"Embeds this instance does not allow; they stay in the content and show as links."},"problems":{"type":"array","items":{"type":"object","properties":{"place":{"description":"Where, such as `field 3` or `content`.","type":["string","null"]},"message":{"type":"string","description":"Explanation naming the template and the place."}},"required":["place","message"],"additionalProperties":false,"description":"A problem."},"description":"Why the template cannot be imported; empty when it can."},"valid":{"type":"boolean","description":"Whether the template can be imported."},"conflict":{"anyOf":[{"type":"object","properties":{"templateId":{"type":"string","format":"uuid","description":"The template with the same name at this level."},"suggestedName":{"type":"string","description":"A new name to use instead, in the caller's language."}},"required":["templateId","suggestedName"],"additionalProperties":false},{"type":"null"}],"description":"A template with the same name at this level, or null."}},"required":["index","name","description","category","language","title","fields","series","document","files","removed","blockedEmbeds","problems","valid","conflict"],"additionalProperties":false,"description":"A template of the uploaded file."},"description":"The templates of the file."},"expiresAt":{"type":"string","format":"date-time","description":"When the preview is discarded."}},"required":["id","fileName","templates","expiresAt"],"additionalProperties":false,"description":"What an import will create. Nothing is saved before it is confirmed."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5aa0","fileName":"change-request.lunedo-template.zip","templates":[{"index":0,"name":"Change request","description":"Planned change with risk and rollback","category":"operations","language":"en","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"series":null,"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"files":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a91","name":"rollout.png","mediaType":"image/png","size":48213}],"removed":{},"blockedEmbeds":[],"problems":[],"valid":true,"conflict":{"templateId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","suggestedName":"Change request (imported)"}}],"expiresAt":"2026-10-18T20:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidTemplateFile`: The file is not a valid Lunedo template file. `nestedTemplateArchive`: The archive contains another archive. `newerTemplateFormat`: The template file was written by a newer Lunedo. `templateArchiveCompression`: A file in the archive is compressed too strongly. `tooManyTemplateFiles`: The archive holds more files than allowed. `tooManyTemplates`: The file holds more templates than allowed. `unexpectedTemplateEntry`: The archive contains an unexpected file. `unsafeTemplateArchive`: The archive contains unsafe entries.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidTemplateFile":{"value":{"type":"urn:lunedo:problem:invalidTemplateFile","title":"The file is not a valid Lunedo template file","status":400,"code":"invalidTemplateFile"}},"nestedTemplateArchive":{"value":{"type":"urn:lunedo:problem:nestedTemplateArchive","title":"The archive contains another archive","status":400,"code":"nestedTemplateArchive"}},"newerTemplateFormat":{"value":{"type":"urn:lunedo:problem:newerTemplateFormat","title":"The template file was written by a newer Lunedo","status":400,"code":"newerTemplateFormat"}},"templateArchiveCompression":{"value":{"type":"urn:lunedo:problem:templateArchiveCompression","title":"A file in the archive is compressed too strongly","status":400,"code":"templateArchiveCompression"}},"tooManyTemplateFiles":{"value":{"type":"urn:lunedo:problem:tooManyTemplateFiles","title":"The archive holds more files than allowed","status":400,"code":"tooManyTemplateFiles"}},"tooManyTemplates":{"value":{"type":"urn:lunedo:problem:tooManyTemplates","title":"The file holds more templates than allowed","status":400,"code":"tooManyTemplates"}},"unexpectedTemplateEntry":{"value":{"type":"urn:lunedo:problem:unexpectedTemplateEntry","title":"The archive contains an unexpected file","status":400,"code":"unexpectedTemplateEntry"}},"unsafeTemplateArchive":{"value":{"type":"urn:lunedo:problem:unsafeTemplateArchive","title":"The archive contains unsafe entries","status":400,"code":"unsafeTemplateArchive"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"408":{"description":"`uploadTimeout`: The upload took too long.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"uploadTimeout":{"value":{"type":"urn:lunedo:problem:uploadTimeout","title":"The upload took too long","status":408,"code":"uploadTimeout"}}}}}},"413":{"description":"`fileTooLarge`: The file is larger than allowed. `templateArchiveTooLarge`: The archive unpacks to more than allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"fileTooLarge":{"value":{"type":"urn:lunedo:problem:fileTooLarge","title":"The file is larger than allowed","status":413,"code":"fileTooLarge"}},"templateArchiveTooLarge":{"value":{"type":"urn:lunedo:problem:templateArchiveTooLarge","title":"The archive unpacks to more than allowed","status":413,"code":"templateArchiveTooLarge"}}}}}},"415":{"description":"`unsupportedMediaType`: The request body has an unsupported type.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unsupportedMediaType":{"value":{"type":"urn:lunedo:problem:unsupportedMediaType","title":"The request body has an unsupported type","status":415,"code":"unsupportedMediaType"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`busy`: The server is busy. `maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"busy":{"value":{"type":"urn:lunedo:problem:busy","title":"The server is busy","status":503,"code":"busy"}},"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}},"507":{"description":"`storageFull`: Storage is almost full.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"storageFull":{"value":{"type":"urn:lunedo:problem:storageFull","title":"Storage is almost full","status":507,"code":"storageFull"}}}}}}}}},"/api/v1/spaces/{spaceId}/template-imports/{importId}":{"delete":{"operationId":"templateFiles.spaceDiscard","summary":"Discard an import preview","description":"Discards your preview and its files. Previews are also discarded after 12 hours.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Templates"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"importId","in":"path","required":true,"description":"ID of the import preview.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `templateImportNotFound`: The import preview does not exist anymore.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"templateImportNotFound":{"value":{"type":"urn:lunedo:problem:templateImportNotFound","title":"The import preview does not exist anymore","status":404,"code":"templateImportNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/template-imports/{importId}/confirm":{"post":{"operationId":"templateFiles.spaceConfirm","summary":"Confirm an import","description":"Imports the templates of your preview into the space. A template whose name exists already needs a decision: replace it (it keeps its ID, so template buttons keep working) or create it under a new name.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Templates"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"importId","in":"path","required":true,"description":"ID of the import preview.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"decisions":{"default":[],"description":"Decisions per template. Templates without a decision are created under their own name.","maxItems":50,"type":"array","items":{"type":"object","properties":{"index":{"type":"integer","minimum":0,"maximum":50,"description":"Position in the file."},"action":{"type":"string","enum":["create","replace","skip"],"description":"`create` a new template, `replace` the template with the same name (it keeps its ID), or `skip` it."},"name":{"description":"Name of a new template; default: the name in the file.","type":"string","maxLength":200}},"required":["index","action"],"additionalProperties":false,"description":"What to do with one template."}},"skipInvalid":{"default":false,"description":"Import the valid templates when others in the file are not valid. Without it, nothing is imported.","type":"boolean"}},"additionalProperties":false,"description":"Confirms an import preview."},"example":{"decisions":[{"index":0,"action":"create","name":"Change request (imported)"}]}}}},"responses":{"200":{"description":"The result.","content":{"application/json":{"schema":{"type":"object","properties":{"created":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"ID of the template. Built-in templates have IDs starting with `builtin:`."},"level":{"type":"string","enum":["builtIn","instance","organization","space"],"description":"Where the template comes from: built in, or from the instance, the organization or the space."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization of an organization template, or null."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space of a space template, or null."},"name":{"type":"string","description":"Name."},"description":{"type":"string","description":"Short description."},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","description":"Title of new pages; `{key}` inserts the value of an input field."},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","description":"How often. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"Weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"Default rhythm."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Default duration in minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false,"description":"Defaults of a series template."},{"type":"null"}],"description":"For a series template: defaults for rhythm and duration of new meeting series; otherwise null."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Article type of articles created from a template of a knowledge base, or null."},"updatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the template last changed, or null for built-in templates. ISO 8601 timestamp in UTC."}},"required":["id","level","organizationId","spaceId","name","description","category","title","fields","document","series","articleType","updatedAt"],"additionalProperties":false,"description":"A page template."},"description":"Templates created."},"replaced":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"ID of the template. Built-in templates have IDs starting with `builtin:`."},"level":{"type":"string","enum":["builtIn","instance","organization","space"],"description":"Where the template comes from: built in, or from the instance, the organization or the space."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization of an organization template, or null."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space of a space template, or null."},"name":{"type":"string","description":"Name."},"description":{"type":"string","description":"Short description."},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","description":"Title of new pages; `{key}` inserts the value of an input field."},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","description":"How often. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"Weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"Default rhythm."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Default duration in minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false,"description":"Defaults of a series template."},{"type":"null"}],"description":"For a series template: defaults for rhythm and duration of new meeting series; otherwise null."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Article type of articles created from a template of a knowledge base, or null."},"updatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the template last changed, or null for built-in templates. ISO 8601 timestamp in UTC."}},"required":["id","level","organizationId","spaceId","name","description","category","title","fields","document","series","articleType","updatedAt"],"additionalProperties":false,"description":"A page template."},"description":"Templates replaced; they keep their IDs."},"skipped":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Templates not imported."}},"required":["created","replaced","skipped"],"additionalProperties":false,"description":"The result of an import."},"example":{"created":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","level":"space","organizationId":null,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","name":"Change request","description":"Planned change with risk and rollback","category":"operations","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"series":null,"articleType":null,"updatedAt":"2026-10-05T08:00:00.000Z"}],"replaced":[],"skipped":0}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidTemplateName`: The template name is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidTemplateName":{"value":{"type":"urn:lunedo:problem:invalidTemplateName","title":"The template name is not valid","status":400,"code":"invalidTemplateName"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `templateImportNotFound`: The import preview does not exist anymore. `templateNotFound`: The template does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"templateImportNotFound":{"value":{"type":"urn:lunedo:problem:templateImportNotFound","title":"The import preview does not exist anymore","status":404,"code":"templateImportNotFound"}},"templateNotFound":{"value":{"type":"urn:lunedo:problem:templateNotFound","title":"The template does not exist","status":404,"code":"templateNotFound"}}}}}},"409":{"description":"`invalidTemplatesInFile`: Some templates in the file are not valid. `templateNameTaken`: A template with this name exists already.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidTemplatesInFile":{"value":{"type":"urn:lunedo:problem:invalidTemplatesInFile","title":"Some templates in the file are not valid","status":409,"code":"invalidTemplatesInFile"}},"templateNameTaken":{"value":{"type":"urn:lunedo:problem:templateNameTaken","title":"A template with this name exists already","status":409,"code":"templateNameTaken"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}},"507":{"description":"`storageFull`: Storage is almost full.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"storageFull":{"value":{"type":"urn:lunedo:problem:storageFull","title":"Storage is almost full","status":507,"code":"storageFull"}}}}}}}}},"/api/v1/spaces/{spaceId}/template-imports/{importId}/files/{fileId}/content":{"get":{"operationId":"templateFiles.spaceImportFile","summary":"Download a file of an import preview","description":"Sends a checked file of your import preview, to show it before you confirm.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Templates"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"importId","in":"path","required":true,"description":"ID of the import preview.","schema":{"type":"string","format":"uuid"}},{"name":"fileId","in":"path","required":true,"description":"ID of the file.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The file. Sent with `Content-Security-Policy: sandbox` and `X-Content-Type-Options: nosniff`; ranges are supported.","content":{"image/png":{"schema":{"type":"string"},"example":""},"image/jpeg":{"schema":{"type":"string"},"example":""},"image/gif":{"schema":{"type":"string"},"example":""},"image/webp":{"schema":{"type":"string"},"example":""},"image/svg+xml":{"schema":{"type":"string"},"example":""},"*/*":{"schema":{"type":"string"},"example":""}}},"206":{"description":"Part of the file, for a request with a `Range` header.","content":{"image/png":{"schema":{"type":"string"},"example":""},"image/jpeg":{"schema":{"type":"string"},"example":""},"image/gif":{"schema":{"type":"string"},"example":""},"image/webp":{"schema":{"type":"string"},"example":""},"image/svg+xml":{"schema":{"type":"string"},"example":""},"*/*":{"schema":{"type":"string"},"example":""}}},"304":{"description":"Not modified: the file matches the `If-None-Match` header."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `templateImportNotFound`: The import preview does not exist anymore.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"templateImportNotFound":{"value":{"type":"urn:lunedo:problem:templateImportNotFound","title":"The import preview does not exist anymore","status":404,"code":"templateImportNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/templates":{"get":{"operationId":"templates.spaceTemplates","summary":"List the templates of a space","description":"Lists the templates defined in the space itself.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Templates"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Templates of the space.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"ID of the template. Built-in templates have IDs starting with `builtin:`."},"level":{"type":"string","enum":["builtIn","instance","organization","space"],"description":"Where the template comes from: built in, or from the instance, the organization or the space."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization of an organization template, or null."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space of a space template, or null."},"name":{"type":"string","description":"Name."},"description":{"type":"string","description":"Short description."},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","description":"Title of new pages; `{key}` inserts the value of an input field."},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","description":"How often. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"Weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"Default rhythm."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Default duration in minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false,"description":"Defaults of a series template."},{"type":"null"}],"description":"For a series template: defaults for rhythm and duration of new meeting series; otherwise null."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Article type of articles created from a template of a knowledge base, or null."},"updatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the template last changed, or null for built-in templates. ISO 8601 timestamp in UTC."}},"required":["id","level","organizationId","spaceId","name","description","category","title","fields","document","series","articleType","updatedAt"],"additionalProperties":false,"description":"A page template."},"description":"Templates."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","level":"space","organizationId":null,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","name":"Change request","description":"Planned change with risk and rollback","category":"operations","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"series":null,"articleType":null,"updatedAt":"2026-10-05T08:00:00.000Z"}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"post":{"operationId":"templates.createSpaceTemplate","summary":"Create a space template","description":"Creates a template for the space.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Templates"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"description":"Name, 1 to 100 characters."},"description":{"default":"","description":"Short description, up to 300 characters.","type":"string","maxLength":300},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","maxLength":255,"description":"Title of new pages, 1 to 255 characters."},"fields":{"maxItems":20,"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Up to 20 input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"description":"Makes the template a series template with these defaults; null or left out for a page template.","anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","enum":["none","daily","weekly","monthly","yearly"],"description":"`none` for no fixed rhythm, otherwise how often the meetings repeat."},"interval":{"default":1,"description":"Every how many days, weeks, months or years. 2 weekly is every two weeks, 3 monthly is quarterly.","type":"integer","minimum":1,"maximum":52},"weekdays":{"description":"For `weekly`: the weekdays of the meetings, at least one.","maxItems":7,"type":"array","items":{"type":"string","enum":["MO","TU","WE","TH","FR","SA","SU"],"description":"Weekday as in iCalendar: `MO` to `SU`."}},"monthDay":{"description":"For `monthly` by date: the day of the month.","type":"integer","minimum":1,"maximum":31},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"For `monthly` by weekday: the weekday, for example `TU`.","type":"string","enum":["MO","TU","WE","TH","FR","SA","SU"]}},"required":["frequency"],"additionalProperties":false,"description":"The rhythm of a series, as the interface offers it."},"durationMinutes":{"type":"integer","minimum":5,"maximum":1440,"description":"Minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false},{"type":"null"}]},"articleType":{"description":"Article type of articles created from the template. Only templates of a knowledge base have one; left out, a change keeps the current type.","anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}]}},"required":["name","category","title","fields","document"],"additionalProperties":false,"description":"A template."},"example":{"name":"Change request","description":"Planned change with risk and rollback","category":"operations","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]}}}}},"responses":{"201":{"description":"The template.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"ID of the template. Built-in templates have IDs starting with `builtin:`."},"level":{"type":"string","enum":["builtIn","instance","organization","space"],"description":"Where the template comes from: built in, or from the instance, the organization or the space."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization of an organization template, or null."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space of a space template, or null."},"name":{"type":"string","description":"Name."},"description":{"type":"string","description":"Short description."},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","description":"Title of new pages; `{key}` inserts the value of an input field."},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","description":"How often. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"Weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"Default rhythm."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Default duration in minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false,"description":"Defaults of a series template."},{"type":"null"}],"description":"For a series template: defaults for rhythm and duration of new meeting series; otherwise null."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Article type of articles created from a template of a knowledge base, or null."},"updatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the template last changed, or null for built-in templates. ISO 8601 timestamp in UTC."}},"required":["id","level","organizationId","spaceId","name","description","category","title","fields","document","series","articleType","updatedAt"],"additionalProperties":false,"description":"A page template."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","level":"space","organizationId":null,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","name":"Change request","description":"Planned change with risk and rollback","category":"operations","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"series":null,"articleType":null,"updatedAt":"2026-10-05T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidDescription`: The description is too long. `invalidDocument`: The document does not match the editor schema. `invalidInput`: The request is not valid. `invalidTemplateFields`: The input fields of the template are not valid. `invalidTemplateName`: The template name is not valid. `invalidTitle`: The title is not valid. `unknownTemplateField`: The template uses an input field that does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidDescription":{"value":{"type":"urn:lunedo:problem:invalidDescription","title":"The description is too long","status":400,"code":"invalidDescription"}},"invalidDocument":{"value":{"type":"urn:lunedo:problem:invalidDocument","title":"The document does not match the editor schema","status":400,"code":"invalidDocument"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidTemplateFields":{"value":{"type":"urn:lunedo:problem:invalidTemplateFields","title":"The input fields of the template are not valid","status":400,"code":"invalidTemplateFields"}},"invalidTemplateName":{"value":{"type":"urn:lunedo:problem:invalidTemplateName","title":"The template name is not valid","status":400,"code":"invalidTemplateName"}},"invalidTitle":{"value":{"type":"urn:lunedo:problem:invalidTitle","title":"The title is not valid","status":400,"code":"invalidTitle"}},"unknownTemplateField":{"value":{"type":"urn:lunedo:problem:unknownTemplateField","title":"The template uses an input field that does not exist","status":400,"code":"unknownTemplateField"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/templates/{templateId}":{"delete":{"operationId":"templates.deleteSpaceTemplate","summary":"Delete a space template","description":"Deletes a template of the space. Pages created from it stay.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Templates"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"templateId","in":"path","required":true,"description":"ID of the template.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"put":{"operationId":"templates.updateSpaceTemplate","summary":"Change a space template","description":"Changes a template of the space. Pages created from it before stay as they are.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Templates"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"templateId","in":"path","required":true,"description":"ID of the template.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":100,"description":"Name, 1 to 100 characters."},"description":{"default":"","description":"Short description, up to 300 characters.","type":"string","maxLength":300},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","maxLength":255,"description":"Title of new pages, 1 to 255 characters."},"fields":{"maxItems":20,"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Up to 20 input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"description":"Makes the template a series template with these defaults; null or left out for a page template.","anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","enum":["none","daily","weekly","monthly","yearly"],"description":"`none` for no fixed rhythm, otherwise how often the meetings repeat."},"interval":{"default":1,"description":"Every how many days, weeks, months or years. 2 weekly is every two weeks, 3 monthly is quarterly.","type":"integer","minimum":1,"maximum":52},"weekdays":{"description":"For `weekly`: the weekdays of the meetings, at least one.","maxItems":7,"type":"array","items":{"type":"string","enum":["MO","TU","WE","TH","FR","SA","SU"],"description":"Weekday as in iCalendar: `MO` to `SU`."}},"monthDay":{"description":"For `monthly` by date: the day of the month.","type":"integer","minimum":1,"maximum":31},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"For `monthly` by weekday: the weekday, for example `TU`.","type":"string","enum":["MO","TU","WE","TH","FR","SA","SU"]}},"required":["frequency"],"additionalProperties":false,"description":"The rhythm of a series, as the interface offers it."},"durationMinutes":{"type":"integer","minimum":5,"maximum":1440,"description":"Minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false},{"type":"null"}]},"articleType":{"description":"Article type of articles created from the template. Only templates of a knowledge base have one; left out, a change keeps the current type.","anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}]}},"required":["name","category","title","fields","document"],"additionalProperties":false,"description":"A template."},"example":{"name":"Change request","description":"Planned change with risk and rollback","category":"operations","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]}}}}},"responses":{"200":{"description":"The template.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"ID of the template. Built-in templates have IDs starting with `builtin:`."},"level":{"type":"string","enum":["builtIn","instance","organization","space"],"description":"Where the template comes from: built in, or from the instance, the organization or the space."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization of an organization template, or null."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space of a space template, or null."},"name":{"type":"string","description":"Name."},"description":{"type":"string","description":"Short description."},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","description":"Title of new pages; `{key}` inserts the value of an input field."},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","description":"How often. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"Weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"Default rhythm."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Default duration in minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false,"description":"Defaults of a series template."},{"type":"null"}],"description":"For a series template: defaults for rhythm and duration of new meeting series; otherwise null."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Article type of articles created from a template of a knowledge base, or null."},"updatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the template last changed, or null for built-in templates. ISO 8601 timestamp in UTC."}},"required":["id","level","organizationId","spaceId","name","description","category","title","fields","document","series","articleType","updatedAt"],"additionalProperties":false,"description":"A page template."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","level":"space","organizationId":null,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","name":"Change request","description":"Planned change with risk and rollback","category":"operations","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"series":null,"articleType":null,"updatedAt":"2026-10-05T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidDescription`: The description is too long. `invalidDocument`: The document does not match the editor schema. `invalidInput`: The request is not valid. `invalidTemplateFields`: The input fields of the template are not valid. `invalidTemplateName`: The template name is not valid. `invalidTitle`: The title is not valid. `unknownTemplateField`: The template uses an input field that does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidDescription":{"value":{"type":"urn:lunedo:problem:invalidDescription","title":"The description is too long","status":400,"code":"invalidDescription"}},"invalidDocument":{"value":{"type":"urn:lunedo:problem:invalidDocument","title":"The document does not match the editor schema","status":400,"code":"invalidDocument"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidTemplateFields":{"value":{"type":"urn:lunedo:problem:invalidTemplateFields","title":"The input fields of the template are not valid","status":400,"code":"invalidTemplateFields"}},"invalidTemplateName":{"value":{"type":"urn:lunedo:problem:invalidTemplateName","title":"The template name is not valid","status":400,"code":"invalidTemplateName"}},"invalidTitle":{"value":{"type":"urn:lunedo:problem:invalidTitle","title":"The title is not valid","status":400,"code":"invalidTitle"}},"unknownTemplateField":{"value":{"type":"urn:lunedo:problem:unknownTemplateField","title":"The template uses an input field that does not exist","status":400,"code":"unknownTemplateField"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/templates/{templateId}/files":{"post":{"operationId":"templateFiles.spaceUpload","summary":"Add an image to a space template","description":"Stores an image for the template. Send the bytes with `Content-Type: application/octet-stream`. PNG, JPEG, GIF, WebP and SVG are accepted up to 5 MB; SVG images are cleaned of scripts and links. Use the returned ID as `attachmentId` of an image in the content and save the template; files the content no longer uses are removed when the template is saved.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Templates"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"templateId","in":"path","required":true,"description":"ID of the template.","schema":{"type":"string","format":"uuid"}},{"name":"name","in":"query","required":true,"description":"Name of the uploaded file. Paths and control characters are removed.","schema":{"type":"string","minLength":1,"maxLength":1020}}],"requestBody":{"required":true,"description":"The bytes of the image.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"201":{"description":"The file.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the file. Content of the template refers to it, for example as `attachmentId` of an image."},"templateId":{"type":"string","format":"uuid","description":"ID of the template."},"name":{"type":"string","description":"File name."},"size":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Size in bytes."},"contentType":{"type":"string","description":"Media type, decided from the content."}},"required":["id","templateId","name","size","contentType"],"additionalProperties":false,"description":"A file of a template."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a91","templateId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","name":"rollout.png","size":48213,"contentType":"image/png"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidFileName`: The file name is not valid. `invalidInput`: The request is not valid. `unsupportedTemplateFile`: Templates hold PNG, JPEG, GIF, WebP and SVG images only.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidFileName":{"value":{"type":"urn:lunedo:problem:invalidFileName","title":"The file name is not valid","status":400,"code":"invalidFileName"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"unsupportedTemplateFile":{"value":{"type":"urn:lunedo:problem:unsupportedTemplateFile","title":"Templates hold PNG, JPEG, GIF, WebP and SVG images only","status":400,"code":"unsupportedTemplateFile"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"408":{"description":"`uploadTimeout`: The upload took too long.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"uploadTimeout":{"value":{"type":"urn:lunedo:problem:uploadTimeout","title":"The upload took too long","status":408,"code":"uploadTimeout"}}}}}},"413":{"description":"`fileTooLarge`: The file is larger than allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"fileTooLarge":{"value":{"type":"urn:lunedo:problem:fileTooLarge","title":"The file is larger than allowed","status":413,"code":"fileTooLarge"}}}}}},"415":{"description":"`unsupportedMediaType`: The request body has an unsupported type.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unsupportedMediaType":{"value":{"type":"urn:lunedo:problem:unsupportedMediaType","title":"The request body has an unsupported type","status":415,"code":"unsupportedMediaType"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`busy`: The server is busy. `maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"busy":{"value":{"type":"urn:lunedo:problem:busy","title":"The server is busy","status":503,"code":"busy"}},"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}},"507":{"description":"`storageFull`: Storage is almost full.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"storageFull":{"value":{"type":"urn:lunedo:problem:storageFull","title":"Storage is almost full","status":507,"code":"storageFull"}}}}}}}}},"/api/v1/spaces/{spaceId}/templates/{templateId}/files/{fileId}/content":{"get":{"operationId":"templateFiles.spaceTemplateFile","summary":"Download a file of a template","description":"Sends a file of a template that can be used in the space: an image the template shows, or a file of a drawing or diagram. Templates of the instance and the organization need edit access to the space.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Templates"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"templateId","in":"path","required":true,"description":"ID of the template.","schema":{"type":"string","format":"uuid"}},{"name":"fileId","in":"path","required":true,"description":"ID of the file.","schema":{"type":"string","format":"uuid"}},{"name":"size","in":"query","required":false,"description":"Size of an image. `display` sends a version whose longest edge is at most 2048 pixels, `preview` one of at most 400 pixels, both as WebP without metadata. The original is sent while no such version exists, for images that are already small enough, and for every other type. Images above 100 megapixels get no smaller version and answer `imageTooLarge`.","schema":{"default":"original","type":"string","enum":["original","display","preview"]}}],"responses":{"200":{"description":"The file. Sent with `Content-Security-Policy: sandbox` and `X-Content-Type-Options: nosniff`; ranges are supported.","content":{"image/png":{"schema":{"type":"string"},"example":""},"image/jpeg":{"schema":{"type":"string"},"example":""},"image/gif":{"schema":{"type":"string"},"example":""},"image/webp":{"schema":{"type":"string"},"example":""},"image/svg+xml":{"schema":{"type":"string"},"example":""},"*/*":{"schema":{"type":"string"},"example":""}}},"206":{"description":"Part of the file, for a request with a `Range` header.","content":{"image/png":{"schema":{"type":"string"},"example":""},"image/jpeg":{"schema":{"type":"string"},"example":""},"image/gif":{"schema":{"type":"string"},"example":""},"image/webp":{"schema":{"type":"string"},"example":""},"image/svg+xml":{"schema":{"type":"string"},"example":""},"*/*":{"schema":{"type":"string"},"example":""}}},"304":{"description":"Not modified: the file matches the `If-None-Match` header."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`imageTooLarge`: The image is too large for a smaller version.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"imageTooLarge":{"value":{"type":"urn:lunedo:problem:imageTooLarge","title":"The image is too large for a smaller version","status":409,"code":"imageTooLarge"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/templates/export":{"post":{"operationId":"templateFiles.spaceExport","summary":"Export space templates","description":"Sends the chosen templates as a template file. Links to pages and spaces, mentions, includes, live diagram references, whiteboard blocks, template buttons, reports bound to pages or spaces and people are removed; the template's own images and external links stay. The file contains no IDs, names of people or titles of other pages.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Templates"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"templateIds":{"default":null,"description":"The templates to export; null for all of this level, at most 50.","anyOf":[{"minItems":1,"maxItems":50,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a template."}},{"type":"null"}]}},"additionalProperties":false,"description":"Which templates to export."},"example":{"templateIds":null}}}},"responses":{"200":{"description":"A template file: JSON for templates without files, otherwise a ZIP archive with `template.json` and the files under `files/`.","content":{"application/json":{"schema":{"type":"string"},"example":"{\n  \"format\": \"lunedo-template\",\n  \"formatVersion\": 1\n}\n"},"application/zip":{"schema":{"type":"string"},"example":"{\n  \"format\": \"lunedo-template\",\n  \"formatVersion\": 1\n}\n"}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `noTemplates`: There are no templates to export. `templateExportTooLarge`: The export would be larger than allowed. `tooManyTemplates`: The file holds more templates than allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"noTemplates":{"value":{"type":"urn:lunedo:problem:noTemplates","title":"There are no templates to export","status":400,"code":"noTemplates"}},"templateExportTooLarge":{"value":{"type":"urn:lunedo:problem:templateExportTooLarge","title":"The export would be larger than allowed","status":400,"code":"templateExportTooLarge"}},"tooManyTemplates":{"value":{"type":"urn:lunedo:problem:tooManyTemplates","title":"The file holds more templates than allowed","status":400,"code":"tooManyTemplates"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `templateNotFound`: The template does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"templateNotFound":{"value":{"type":"urn:lunedo:problem:templateNotFound","title":"The template does not exist","status":404,"code":"templateNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/templates/export-summary":{"post":{"operationId":"templateFiles.spaceExportSummary","summary":"Check an export of space templates","description":"Tells per template what an export removes because it cannot work in another instance, before anything is downloaded.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Templates"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"templateIds":{"default":null,"description":"The templates to export; null for all of this level, at most 50.","anyOf":[{"minItems":1,"maxItems":50,"type":"array","items":{"type":"string","format":"uuid","description":"ID of a template."}},{"type":"null"}]}},"additionalProperties":false,"description":"Which templates to export."},"example":{"templateIds":["01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70"]}}}},"responses":{"200":{"description":"What the export contains.","content":{"application/json":{"schema":{"type":"object","properties":{"templates":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Name of the template."},"files":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of files in the export."},"removed":{"type":"object","propertyNames":{"type":"string","enum":["pageLink","mention","include","diagramReference","whiteboard","templateButton","report","roadmap","person","comment","meetingTopic","file","unsupportedMacro"]},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"What is removed because it cannot work in another instance, by kind: `pageLink` (links to pages and spaces), `mention`, `include`, `diagramReference`, `whiteboard`, `templateButton`, `report`, `roadmap`, `person`, `comment`, `meetingTopic`, `file` (files that are not part of the template or not images) and `unsupportedMacro`."}},"required":["name","files","removed"],"additionalProperties":false,"description":"A template of the export."},"description":"The templates in the order of the file."}},"required":["templates"],"additionalProperties":false,"description":"What an export will contain."},"example":{"templates":[{"name":"Change request","files":1,"removed":{"pageLink":2,"mention":1}}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `templateNotFound`: The template does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"templateNotFound":{"value":{"type":"urn:lunedo:problem:templateNotFound","title":"The template does not exist","status":404,"code":"templateNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/templates/from-page":{"post":{"operationId":"templates.saveFromPage","summary":"Save a page as a space template","description":"Creates a space template from the current content of a page of the space, including its draft. Editors can do this; space admins can then add input fields. When the page or a page above it has a view restriction, everyone who can use the space's templates would see its content, so the request must confirm this with `confirmRestricted`; the save is then recorded in the audit log.\n\nRequires the permission `space.edit` on the space in `spaceId`.","tags":["Templates"],"x-lunedo-permission":{"action":"space.edit","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"pageId":{"type":"string","format":"uuid","description":"The page whose current content becomes the template."},"name":{"type":"string","maxLength":100,"description":"Name, 1 to 100 characters."},"description":{"default":"","description":"Short description.","type":"string","maxLength":300},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"confirmRestricted":{"default":false,"description":"Confirms that everyone who can use the space's templates may see the content of a page with a view restriction. Without it, saving a restricted page is refused with `templateFromRestrictedPage`.","type":"boolean"}},"required":["pageId","name","category"],"additionalProperties":false,"description":"A page to save as a space template."},"example":{"pageId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","name":"Runbook","category":"operations"}}}},"responses":{"201":{"description":"The template.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"ID of the template. Built-in templates have IDs starting with `builtin:`."},"level":{"type":"string","enum":["builtIn","instance","organization","space"],"description":"Where the template comes from: built in, or from the instance, the organization or the space."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization of an organization template, or null."},"spaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Space of a space template, or null."},"name":{"type":"string","description":"Name."},"description":{"type":"string","description":"Short description."},"category":{"type":"string","enum":["meetings","decisions","projects","engineering","operations","knowledge","teams"],"description":"Category in the gallery: meetings, decisions, projects, engineering, operations, knowledge or teams."},"title":{"type":"string","description":"Title of new pages; `{key}` inserts the value of an input field."},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40,"description":"Key of the field, used as `{key}` in the title and by template field nodes in the content."},"label":{"type":"string","maxLength":100,"description":"Label shown when the page is created."},"type":{"type":"string","enum":["text","date","person","choice"],"description":"`text`, `date` (filled with today by default), `person` (inserted as a mention) or `choice`."},"required":{"type":"boolean","description":"Whether a value is required."},"options":{"description":"Options of a choice field.","maxItems":30,"type":"array","items":{"type":"string","maxLength":100}}},"required":["key","label","type","required"],"additionalProperties":false,"description":"An input field asked for when a page is created from the template."},"description":"Input fields."},"document":{"description":"Page content as ProseMirror JSON, as defined by the editor schema: an object with `type: \"doc\"` and `content`.","$ref":"#/components/schemas/Schema113ae44d8375"},"series":{"anyOf":[{"type":"object","properties":{"rhythm":{"type":"object","properties":{"frequency":{"type":"string","description":"How often. New values can be added in later versions; handle unknown values.","x-extensible-enum":["none","daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Every how many units."},"weekdays":{"description":"Weekdays.","type":"array","items":{"type":"string"}},"monthDay":{"description":"Day of the month.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weekOfMonth":{"description":"For `monthly` by weekday: 1 to 4 for the first to fourth, -1 for the last.","type":"integer","minimum":-1,"maximum":4},"weekday":{"description":"Weekday.","type":"string"}},"required":["frequency","interval"],"additionalProperties":false,"description":"Default rhythm."},"durationMinutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Default duration in minutes."}},"required":["rhythm","durationMinutes"],"additionalProperties":false,"description":"Defaults of a series template."},{"type":"null"}],"description":"For a series template: defaults for rhythm and duration of new meeting series; otherwise null."},"articleType":{"anyOf":[{"type":"string","description":"Type of an article: `howTo` (step-by-step instructions) or `troubleshooting` (symptom, cause and solution). New values can be added in later versions; handle unknown values.","x-extensible-enum":["howTo","troubleshooting"]},{"type":"null"}],"description":"Article type of articles created from a template of a knowledge base, or null."},"updatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the template last changed, or null for built-in templates. ISO 8601 timestamp in UTC."}},"required":["id","level","organizationId","spaceId","name","description","category","title","fields","document","series","articleType","updatedAt"],"additionalProperties":false,"description":"A page template."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a70","level":"space","organizationId":null,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","name":"Change request","description":"Planned change with risk and rollback","category":"operations","title":"Change {name}","fields":[{"key":"name","label":"Name of the change","type":"text","required":true}],"document":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Connect through WireGuard."}]}]},"series":null,"articleType":null,"updatedAt":"2026-10-05T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidDescription`: The description is too long. `invalidInput`: The request is not valid. `invalidTemplateName`: The template name is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidDescription":{"value":{"type":"urn:lunedo:problem:invalidDescription","title":"The description is too long","status":400,"code":"invalidDescription"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidTemplateName":{"value":{"type":"urn:lunedo:problem:invalidTemplateName","title":"The template name is not valid","status":400,"code":"invalidTemplateName"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`templateFromRestrictedPage`: The page is restricted; saving it as a template needs a confirmation.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"templateFromRestrictedPage":{"value":{"type":"urn:lunedo:problem:templateFromRestrictedPage","title":"The page is restricted; saving it as a template needs a confirmation","status":409,"code":"templateFromRestrictedPage"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/templates/from-page/files":{"get":{"operationId":"templateFiles.pageFiles","summary":"Check the files a page would give a template","description":"Tells how many files of the page a new template would take over, and whether the page is restricted. Files of a restricted page become visible to everyone who can use the template.\n\nRequires the permission `space.edit` on the space in `spaceId`.","tags":["Templates"],"x-lunedo-permission":{"action":"space.edit","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"pageId","in":"query","required":true,"description":"The page to save as a template.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Files and restriction of the page.","content":{"application/json":{"schema":{"type":"object","properties":{"files":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Files the template would take over."},"restricted":{"type":"boolean","description":"Whether the page or a page above it has a view restriction."}},"required":["files","restricted"],"additionalProperties":false,"description":"What saving the page as a template would share."},"example":{"files":2,"restricted":true}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/trash":{"get":{"operationId":"trash.spaceTrash","summary":"List the trash of a space","description":"Lists deleted pages, folders and links still in the space trash, newest first, with who deleted them and when they will be removed for good. In a confidential space, its space admins also get the entries of the second stage, which only they can restore.\n\nRequires the permission `space.trash` on the space in `spaceId`.","tags":["Trash"],"x-lunedo-permission":{"action":"space.trash","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Trash entries.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the trash entry."},"spaceId":{"type":"string","format":"uuid","description":"Space of the entry."},"spaceKey":{"type":"string","description":"Key of the space."},"spaceName":{"type":"string","description":"Name of the space."},"kind":{"type":"string","enum":["items","space"],"description":"`items` for deleted pages, folders or links, `space` for a deleted space."},"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The deleted item, or null for a space."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the deleted item in the addresses of the app, or null for a space."},"itemKind":{"anyOf":[{"type":"string","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},{"type":"null"}],"description":"Kind of the deleted item, or null for a space. New values can be added in later versions; handle unknown values."},"title":{"type":"string","description":"Title of the deleted item, or name of the space."},"descendants":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of descendants deleted with the item."},"stage":{"anyOf":[{"type":"number","const":1},{"type":"number","const":2}],"description":"1 while the entry is in the space trash, 2 after that period or after the trash was emptied; then only organization administrators can restore it."},"deletedAt":{"type":"string","format":"date-time","description":"When it was deleted. ISO 8601 timestamp in UTC."},"deletedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when the account no longer exists.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who deleted it."},"stageTwoAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the entry reached stage 2, or null. ISO 8601 timestamp in UTC."},"removedAt":{"type":"string","format":"date-time","description":"When the entry will be deleted permanently, by the current retention settings. ISO 8601 timestamp in UTC."},"formerParentEntryId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The trash entry of the page or folder this item was below, when that one is in the same trash list; restoring with `withParents=true` restores both. Null otherwise."}},"required":["id","spaceId","spaceKey","spaceName","kind","itemId","number","itemKind","title","descendants","stage","deletedAt","deletedBy","stageTwoAt","removedAt","formerParentEntryId"],"additionalProperties":false,"description":"An entry of the trash."},"description":"Trash entries."},"example":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a60","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","kind":"items","itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a41","number":1041,"itemKind":"page","title":"Old VPN (OpenVPN) setup","descendants":2,"stage":1,"deletedAt":"2026-10-02T10:00:00.000Z","deletedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Lukas Hofer"},"stageTwoAt":null,"removedAt":"2027-02-14T10:00:00.000Z","formerParentEntryId":null}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/trash/{entryId}/restore":{"post":{"operationId":"trash.restoreInSpace","summary":"Restore from the trash","description":"Puts a trash entry back at its old place, or at the top level of the space when that place no longer exists. When the former parent page is in the trash and the content would lose a view restriction it inherited, the restore is refused with `restrictedParentInTrash`; repeat it with `withParents=true` to restore the parent pages with it. `withParents=true` also restores a former parent page that is in the trash without a restriction, so the content returns below it.\n\nRequires the permission `space.trash` on the space in `spaceId`.","tags":["Trash"],"x-lunedo-permission":{"action":"space.trash","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"entryId","in":"path","required":true,"description":"ID of the trash entry.","schema":{"type":"string","format":"uuid"}},{"name":"withParents","in":"query","required":false,"description":"`true` also restores the former parent pages from the trash when the content would otherwise lose a view restriction it inherited. It needs the right to restore each of them.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"Where it went.","content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The restored item, or null for a space."},"number":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the restored item in the addresses of the app, or null for a space."},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Where the item went: its parent, or null for the top level."},"parentEntries":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of trash entries of former parent pages restored with it, so it keeps the view restrictions it inherited."}},"required":["itemId","number","parentId","parentEntries"],"additionalProperties":false,"description":"Where the restored content went."},"example":{"itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a41","number":1041,"parentId":null,"parentEntries":0}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`restrictedParentInTrash`: The content was below a restricted page that is in the trash.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"restrictedParentInTrash":{"value":{"type":"urn:lunedo:problem:restrictedParentInTrash","title":"The content was below a restricted page that is in the trash","status":409,"code":"restrictedParentInTrash"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/trash/empty":{"post":{"operationId":"trash.empty","summary":"Empty the trash of a space","description":"Moves every entry of the space trash to the second stage. Organization administrators can still restore them until the second period ends.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Trash"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Number of entries moved.","content":{"application/json":{"schema":{"type":"object","properties":{"entries":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Entries moved to the second stage."}},"required":["entries"],"additionalProperties":false,"description":"The result."},"example":{"entries":3}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/unowned-items":{"get":{"operationId":"ownership.spaceUnowned","summary":"List items without an owner in a space","description":"Lists items of the space whose owner was deactivated or left the organization, and items that never had an owner. Only items the caller can open are listed; `hidden` counts the others. Giving an item a new owner removes it from the list; a returning owner is owner again unless someone else was given the item.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Ownership and status"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"description":"Cursor from `nextCursor` of the previous page.","schema":{"type":"string","maxLength":2000}}],"responses":{"200":{"description":"The items.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the item."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app."},"spaceId":{"type":"string","format":"uuid","description":"Space of the item."},"spaceKey":{"type":"string","description":"Key of the space."},"spaceName":{"type":"string","description":"Name of the space."},"kind":{"type":"string","description":"Kind of the item. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title of the item."},"formerOwner":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the person."},"name":{"description":"Name of the person, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"The owner who left, or null when the item never had one."},"reason":{"type":"string","enum":["none","deactivated","membershipEnded"],"description":"Why the item has no owner: `none` (never had one), `deactivated` (the account was deactivated) or `membershipEnded` (the person is no longer a member of the organization)."}},"required":["id","number","spaceId","spaceKey","spaceName","kind","title","formerOwner","reason"],"additionalProperties":false,"description":"An item without an active owner."},"description":"Items, by title, up to 100 per page."},"hidden":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of further items without an owner that the caller cannot open, for example restricted pages. Remove their restriction or ask someone who can open them."},"nextCursor":{"description":"Cursor for the next page, or null on the last page.","type":["string","null"]}},"required":["items","hidden","nextCursor"],"additionalProperties":false,"description":"Items without an active owner."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":1042,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a30","spaceKey":"ITOPS","spaceName":"IT Operations","kind":"page","title":"Restart the VPN gateway","formerOwner":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Weber"},"reason":"deactivated"}],"hidden":0,"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/spaces/{spaceId}/visibility":{"put":{"operationId":"spaces.changeVisibility","summary":"Change the visibility of a space","description":"Changes who can read the space besides its holders. Preview the change first and confirm it with the people it affects in view. The change is audited. A knowledge base sets its readers through its audience instead.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"visibility":{"type":"string","enum":["private","organization","instance"],"description":"Who can read the space besides its holders: `private` (only holders), `organization` (every member of the organization) or `instance` (every internal user of the instance)."}},"required":["visibility"],"additionalProperties":false,"description":"The visibility."},"example":{"visibility":"organization"}}}},"responses":{"200":{"description":"The changed space.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space, 2 to 10 letters or digits. It appears in addresses."},"type":{"type":"string","description":"Type of the space: `standard` for pages, blog posts, meetings and whiteboards, or `knowledgeBase` for articles in categories. Chosen at creation. New values can be added in later versions; handle unknown values.","x-extensible-enum":["standard","knowledgeBase"]},"audience":{"anyOf":[{"type":"string","description":"Who may read a knowledge base: `public` (everyone, also without signing in, once the portal exists; in Lunedo all internal users), `signedIn` (all internal users of the instance), `groups` (members of the groups that hold the reader role) or `portal` (portal accounts; in Lunedo only holders of a role). Categories and articles can narrow it with view restrictions, never widen it. New values can be added in later versions; handle unknown values.","x-extensible-enum":["public","signedIn","groups","portal"]},{"type":"null"}],"description":"Who may read the knowledge base, or null for other spaces."},"name":{"type":"string","description":"Name of the space. Empty for a personal space that has no name of its own."},"displayName":{"type":"string","description":"Name to show: the name of the space, or for a personal space without a name of its own \"Personal space of\" and the owner's name, in the owner's language."},"description":{"type":"string","description":"Short description, up to 1000 characters."},"visibility":{"type":"string","enum":["private","organization","instance"],"description":"Who can read the space besides its holders: `private` (only holders), `organization` (every member of the organization) or `instance` (every internal user of the instance)."},"discoverable":{"type":"boolean","description":"Whether members of the organization can find the space and ask for access without reading it."},"confidential":{"type":"boolean","description":"Whether the space is confidential: only its members can read it, and administrators cannot give themselves or others access. Chosen at creation."},"oneOnOne":{"type":"boolean","description":"Whether the space holds a one-on-one."},"quarantined":{"type":"boolean","description":"Whether the space holds an import that is not accepted yet. Only the importing administrator and the reviewers can read it."},"organizationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Organization the space belongs to, or null for a personal space."},"organizationName":{"description":"Name of the organization, or null for a personal space.","type":["string","null"]},"personal":{"type":"boolean","description":"Whether this is a personal space."},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Owner of a personal space, or null."},"ownerName":{"description":"Name of the owner of a personal space, or null.","type":["string","null"]},"overviewItemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The overview page of the space, or null for a knowledge base."},"overviewItemNumber":{"anyOf":[{"type":"integer","minimum":1,"maximum":9007199254740991},{"type":"null"}],"description":"Number of the overview page in the addresses of the app, or null for a knowledge base."},"archived":{"type":"boolean","description":"Whether the space is archived. Archived spaces are read-only."},"exportEnabled":{"type":"boolean","description":"Whether pages and the space can be exported. Space administrators turn export off and on; it applies to everyone. Turning it off does not prevent copying content."},"createdAt":{"type":"string","format":"date-time","description":"When the space was created. ISO 8601 timestamp in UTC."},"updatedAt":{"type":"string","format":"date-time","description":"When the settings of the space last changed. ISO 8601 timestamp in UTC."}},"required":["id","key","type","audience","name","displayName","description","visibility","discoverable","confidential","oneOnOne","quarantined","organizationId","organizationName","personal","ownerId","ownerName","overviewItemId","overviewItemNumber","archived","exportEnabled","createdAt","updatedAt"],"additionalProperties":false,"description":"A space."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","key":"ITOPS","type":"standard","audience":null,"name":"IT Operations","displayName":"IT Operations","description":"Runbooks and how-tos of the IT team","visibility":"organization","discoverable":false,"confidential":false,"oneOnOne":false,"quarantined":false,"organizationId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a6b","organizationName":"Example Inc.","personal":false,"ownerId":null,"ownerName":null,"overviewItemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a11","overviewItemNumber":1001,"archived":false,"exportEnabled":true,"createdAt":"2026-10-05T08:00:00.000Z","updatedAt":"2026-10-05T08:00:00.000Z"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `personalSpaceVisibility`: Personal spaces are always private.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"personalSpaceVisibility":{"value":{"type":"urn:lunedo:problem:personalSpaceVisibility","title":"Personal spaces are always private","status":400,"code":"personalSpaceVisibility"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`knowledgeBaseVisibility`: A knowledge base is opened by its audience. `privateSpaceBroadGrant`: A private space gives roles to people and groups only.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"knowledgeBaseVisibility":{"value":{"type":"urn:lunedo:problem:knowledgeBaseVisibility","title":"A knowledge base is opened by its audience","status":409,"code":"knowledgeBaseVisibility"}},"privateSpaceBroadGrant":{"value":{"type":"urn:lunedo:problem:privateSpaceBroadGrant","title":"A private space gives roles to people and groups only","status":409,"code":"privateSpaceBroadGrant"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/visibility/preview":{"post":{"operationId":"spaces.previewVisibility","summary":"Preview a visibility change","description":"Shows who would gain or lose read access if the visibility changed. Nothing is changed.\n\nRequires the permission `space.manage` on the space in `spaceId`.","tags":["Spaces"],"x-lunedo-permission":{"action":"space.manage","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"visibility":{"type":"string","enum":["private","organization","instance"],"description":"Who can read the space besides its holders: `private` (only holders), `organization` (every member of the organization) or `instance` (every internal user of the instance)."}},"required":["visibility"],"additionalProperties":false,"description":"The visibility."},"example":{"visibility":"organization"}}}},"responses":{"200":{"description":"The change in access.","content":{"application/json":{"schema":{"type":"object","properties":{"gaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who get access."},"losing":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who lose access."},"raised":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role rises."},"lowered":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role drops."},"unlisted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of affected people the caller may not see; they are counted but not listed."},"truncated":{"type":"boolean","description":"Whether `changes` lists only the first 100 people."},"changes":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."},"before":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role before the change, or null for no access."},"after":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role after the change, or null for no access."}},"required":["accountId","name","before","after"],"additionalProperties":false,"description":"How the access of one person changes."},"description":"People whose access changes, ordered by name."}},"required":["gaining","losing","raised","lowered","unlisted","truncated","changes"],"additionalProperties":false,"description":"Who gains, loses or changes access."},"example":{"gaining":1,"losing":0,"raised":0,"lowered":0,"unlisted":0,"truncated":false,"changes":[{"accountId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger","before":null,"after":"reader"}]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`privateSpaceBroadGrant`: A private space gives roles to people and groups only.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"privateSpaceBroadGrant":{"value":{"type":"urn:lunedo:problem:privateSpaceBroadGrant","title":"A private space gives roles to people and groups only","status":409,"code":"privateSpaceBroadGrant"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/spaces/{spaceId}/watch":{"delete":{"operationId":"watches.resetSpace","summary":"Remove the watch state of a space","description":"The caller then neither watches nor mutes the space; pages keep their own states.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Watching"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The watch state that applies now.","content":{"application/json":{"schema":{"type":"object","properties":{"own":{"anyOf":[{"type":"object","properties":{"state":{"type":"string","enum":["watching","muted","notWatching"],"description":"`watching` delivers changes and comments, `muted` silences everything from it, `notWatching` stops watching it even when its space or meeting series is watched."},"keepActionable":{"type":"boolean","description":"Whether mentions, assigned tasks, shares with the person and access requests they can decide still arrive while muted."},"automatic":{"type":"boolean","description":"True when the caller watches because they created, edited or commented on it."}},"required":["state","keepActionable","automatic"],"additionalProperties":false},{"type":"null"}],"description":"The state the caller set for this item or space, or null."},"effective":{"anyOf":[{"type":"object","properties":{"state":{"type":"string","enum":["watching","muted","notWatching"],"description":"`watching` delivers changes and comments, `muted` silences everything from it, `notWatching` stops watching it even when its space or meeting series is watched."},"keepActionable":{"type":"boolean","description":"Whether mentions, assigned tasks, shares with the person and access requests they can decide still arrive while muted."},"source":{"type":"string","enum":["target","series","space"],"description":"Where the state comes from: the item or space itself, its meeting series or its space."}},"required":["state","keepActionable","source"],"additionalProperties":false},{"type":"null"}],"description":"The state that applies, or null when nothing is set."}},"required":["own","effective"],"additionalProperties":false,"description":"Whether the caller watches or muted the item or space."},"example":{"own":null,"effective":{"state":"watching","keepActionable":true,"source":"space"}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"get":{"operationId":"watches.spaceStatus","summary":"Get the watch state of a space","description":"Shows whether the caller watches or muted the space.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Watching"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The caller's watch state.","content":{"application/json":{"schema":{"type":"object","properties":{"own":{"anyOf":[{"type":"object","properties":{"state":{"type":"string","enum":["watching","muted","notWatching"],"description":"`watching` delivers changes and comments, `muted` silences everything from it, `notWatching` stops watching it even when its space or meeting series is watched."},"keepActionable":{"type":"boolean","description":"Whether mentions, assigned tasks, shares with the person and access requests they can decide still arrive while muted."},"automatic":{"type":"boolean","description":"True when the caller watches because they created, edited or commented on it."}},"required":["state","keepActionable","automatic"],"additionalProperties":false},{"type":"null"}],"description":"The state the caller set for this item or space, or null."},"effective":{"anyOf":[{"type":"object","properties":{"state":{"type":"string","enum":["watching","muted","notWatching"],"description":"`watching` delivers changes and comments, `muted` silences everything from it, `notWatching` stops watching it even when its space or meeting series is watched."},"keepActionable":{"type":"boolean","description":"Whether mentions, assigned tasks, shares with the person and access requests they can decide still arrive while muted."},"source":{"type":"string","enum":["target","series","space"],"description":"Where the state comes from: the item or space itself, its meeting series or its space."}},"required":["state","keepActionable","source"],"additionalProperties":false},{"type":"null"}],"description":"The state that applies, or null when nothing is set."}},"required":["own","effective"],"additionalProperties":false,"description":"Whether the caller watches or muted the item or space."},"example":{"own":null,"effective":{"state":"watching","keepActionable":true,"source":"space"}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"put":{"operationId":"watches.watchSpace","summary":"Watch, mute or stop watching a space","description":"Watching a space delivers changes and comments on everything in it the caller can read. Muting it silences everything from it, except mentions, assigned tasks, shares with the caller and access requests the caller can decide when `keepActionable` is true.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Watching"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"state":{"type":"string","enum":["watching","muted","notWatching"],"description":"`watching` delivers changes and comments, `muted` silences everything from it, `notWatching` stops watching it even when its space or meeting series is watched."},"keepActionable":{"description":"For `muted`: still deliver mentions, assigned tasks, shares with the caller and access requests the caller can decide. Default true.","type":"boolean"}},"required":["state"],"additionalProperties":false,"description":"The new state."},"example":{"state":"watching"}}}},"responses":{"200":{"description":"The new watch state.","content":{"application/json":{"schema":{"type":"object","properties":{"own":{"anyOf":[{"type":"object","properties":{"state":{"type":"string","enum":["watching","muted","notWatching"],"description":"`watching` delivers changes and comments, `muted` silences everything from it, `notWatching` stops watching it even when its space or meeting series is watched."},"keepActionable":{"type":"boolean","description":"Whether mentions, assigned tasks, shares with the person and access requests they can decide still arrive while muted."},"automatic":{"type":"boolean","description":"True when the caller watches because they created, edited or commented on it."}},"required":["state","keepActionable","automatic"],"additionalProperties":false},{"type":"null"}],"description":"The state the caller set for this item or space, or null."},"effective":{"anyOf":[{"type":"object","properties":{"state":{"type":"string","enum":["watching","muted","notWatching"],"description":"`watching` delivers changes and comments, `muted` silences everything from it, `notWatching` stops watching it even when its space or meeting series is watched."},"keepActionable":{"type":"boolean","description":"Whether mentions, assigned tasks, shares with the person and access requests they can decide still arrive while muted."},"source":{"type":"string","enum":["target","series","space"],"description":"Where the state comes from: the item or space itself, its meeting series or its space."}},"required":["state","keepActionable","source"],"additionalProperties":false},{"type":"null"}],"description":"The state that applies, or null when nothing is set."}},"required":["own","effective"],"additionalProperties":false,"description":"Whether the caller watches or muted the item or space."},"example":{"own":null,"effective":{"state":"watching","keepActionable":true,"source":"space"}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/starred":{"get":{"operationId":"home.starred","summary":"List starred items and spaces","description":"Lists what the caller starred, limited to items and spaces the caller can still read.\n\nRequires the permission `instance.content.view` on the instance.","tags":["Home"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"responses":{"200":{"description":"Starred items and spaces.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the page or blog post."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the item in the addresses of the app."},"kind":{"type":"string","description":"Kind of the item. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","folder","link","blogPost","meetingSeries","meetingTopic","whiteboard"]},"title":{"type":"string","description":"Title readers see."},"spaceId":{"type":"string","format":"uuid","description":"Space of the item."},"spaceKey":{"type":"string","description":"Key of that space."},"spaceName":{"type":"string","description":"Name of that space."},"mySpace":{"type":"boolean","description":"Whether the item lies in the caller's own personal space."},"starredAt":{"type":"string","format":"date-time","description":"When it was starred. ISO 8601 timestamp in UTC."}},"required":["id","number","kind","title","spaceId","spaceKey","spaceName","mySpace","starredAt"],"additionalProperties":false,"description":"A starred page or post."},"description":"Starred pages and blog posts the caller can read, newest first."},"spaces":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the space."},"key":{"type":"string","description":"Key of the space."},"name":{"type":"string","description":"Name of the space. Empty for a personal space without a name."},"personal":{"type":"boolean","description":"Whether it is a personal space."},"mySpace":{"type":"boolean","description":"Whether it is the caller's own personal space."},"starredAt":{"type":"string","format":"date-time","description":"When it was starred. ISO 8601 timestamp in UTC."}},"required":["id","key","name","personal","mySpace","starredAt"],"additionalProperties":false,"description":"A starred space."},"description":"Starred spaces the caller can read, newest first."}},"required":["items","spaces"],"additionalProperties":false,"description":"What the caller starred."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"kind":"page","title":"VPN access for remote staff","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations","mySpace":false,"starredAt":"2026-10-06T08:00:00.000Z"}],"spaces":[]}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `personalOnly`: Only people have this personal data.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"personalOnly":{"value":{"type":"urn:lunedo:problem:personalOnly","title":"Only people have this personal data","status":400,"code":"personalOnly"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/starred/items/{itemId}":{"delete":{"operationId":"home.unstarItem","summary":"Remove the star from a page or blog post","description":"Removing a star that does not exist changes nothing.\n\nRequires the permission `item.view` on the item in `itemId`.","tags":["Home"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the page or blog post.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"put":{"operationId":"home.starItem","summary":"Star a page or blog post","description":"Stars are personal; nobody else sees them.\n\nRequires the permission `item.view` on the item in `itemId`.","tags":["Home"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the page or blog post.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `personalOnly`: Only people have this personal data.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"personalOnly":{"value":{"type":"urn:lunedo:problem:personalOnly","title":"Only people have this personal data","status":400,"code":"personalOnly"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`tooManyStars`: Too many starred items.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"tooManyStars":{"value":{"type":"urn:lunedo:problem:tooManyStars","title":"Too many starred items","status":409,"code":"tooManyStars"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/starred/spaces/{spaceId}":{"delete":{"operationId":"home.unstarSpace","summary":"Remove the star from a space","description":"Removing a star that does not exist changes nothing.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Home"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}},"put":{"operationId":"home.starSpace","summary":"Star a space","description":"Stars are personal; nobody else sees them.\n\nRequires the permission `space.view` on the space in `spaceId`.","tags":["Home"],"x-lunedo-permission":{"action":"space.view","resource":"space","parameter":"spaceId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"spaceId","in":"path","required":true,"description":"ID of the space.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `personalOnly`: Only people have this personal data.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"personalOnly":{"value":{"type":"urn:lunedo:problem:personalOnly","title":"Only people have this personal data","status":400,"code":"personalOnly"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`tooManyStars`: Too many starred items.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"tooManyStars":{"value":{"type":"urn:lunedo:problem:tooManyStars","title":"Too many starred items","status":409,"code":"tooManyStars"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/tasks":{"get":{"operationId":"tasks.list","summary":"List tasks","description":"Lists tasks of published content the caller can read, across all spaces, with counts. With `assignee=me` this is the caller's list of tasks; the task report block uses the same filters. Overdue relates to today in the caller's time zone.\n\nRequires the permission `instance.content.view` on the instance.","tags":["Tasks"],"x-lunedo-permission":{"action":"instance.content.view","resource":"instance"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"assignee","in":"query","required":false,"description":"`me` for the caller's tasks, or an account ID. Leave it out for everyone.","schema":{"anyOf":[{"type":"string","const":"me"},{"type":"string","format":"uuid","description":"Account ID."}]}},{"name":"assignedBy","in":"query","required":false,"description":"`me` for tasks the caller assigned, or an account ID of the person who assigned them.","schema":{"anyOf":[{"type":"string","const":"me"},{"type":"string","format":"uuid","description":"Account ID."}]}},{"name":"spaceId","in":"query","required":false,"description":"Only tasks in this space.","schema":{"type":"string","format":"uuid"}},{"name":"seriesId","in":"query","required":false,"description":"Only tasks written in the meetings of this meeting series. Meetings that were skipped are left out.","schema":{"type":"string","format":"uuid"}},{"name":"pageIds","in":"query","required":false,"description":"Only tasks on these pages and their descendants. Up to 20 page IDs, separated by commas.","schema":{"type":"string","maxLength":800}},{"name":"labels","in":"query","required":false,"description":"Only tasks on pages with at least one of these labels. Up to 20 labels, separated by commas.","schema":{"type":"string","maxLength":2100}},{"name":"status","in":"query","required":false,"description":"`open` (default), `done` or `all`.","schema":{"default":"open","type":"string","enum":["open","done","all"]}},{"name":"due","in":"query","required":false,"description":"`any` (default), `overdue`, `next7Days` and `next30Days` (including overdue ones) or `none` for tasks without a due date.","schema":{"default":"any","type":"string","enum":["any","overdue","next7Days","next30Days","none"]}},{"name":"sort","in":"query","required":false,"description":"`due` (default, tasks without a due date last), `text`, `item` (title of the page), `assignedBy` or `assignee` (names).","schema":{"default":"due","type":"string","enum":["due","text","item","assignedBy","assignee"]}},{"name":"direction","in":"query","required":false,"description":"`asc` (default) or `desc`.","schema":{"default":"asc","type":"string","enum":["asc","desc"]}},{"name":"cursor","in":"query","required":false,"description":"Cursor from `nextCursor` of the previous page.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","required":false,"description":"Maximum number of tasks, 1 to 200.","schema":{"default":100,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"The tasks.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the task."},"text":{"type":"string","description":"Text of the task, without formatting, up to 500 characters."},"done":{"type":"boolean","description":"Whether the task is done."},"dueDate":{"description":"Due date as `YYYY-MM-DD`, or null.","type":["string","null"]},"overdue":{"type":"boolean","description":"Whether the task is open and its due date lies before today in the caller's time zone."},"assignee":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"The assignee, or null."},"assignedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"type":"string","description":"Name."}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who assigned the task to the assignee when publishing, or null."},"item":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Page or blog post with the task."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of that item in the addresses of the app."},"kind":{"type":"string","description":"Kind of that item. New values can be added in later versions; handle unknown values.","x-extensible-enum":["page","blogPost"]},"title":{"type":"string","description":"Its title."},"spaceId":{"type":"string","format":"uuid","description":"Its space."},"spaceKey":{"type":"string","description":"Key of the space."},"spaceName":{"type":"string","description":"Name of the space."}},"required":["id","number","kind","title","spaceId","spaceKey","spaceName"],"additionalProperties":false,"description":"Where the task is."}},"required":["id","text","done","dueDate","overdue","assignee","assignedBy","item"],"additionalProperties":false,"description":"A task from published content."},"description":"Tasks in the order of `sort`; by default by due date, tasks without one last."},"counts":{"type":"object","properties":{"open":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Open tasks that match the filters other than the status."},"done":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Done tasks that match the filters other than the status."},"overdue":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Open tasks among them that are overdue."}},"required":["open","done","overdue"],"additionalProperties":false,"description":"Counts over all pages of the result."},"nextCursor":{"description":"Cursor for the next page, or null on the last page.","type":["string","null"]}},"required":["items","counts","nextCursor"],"additionalProperties":false,"description":"Tasks."},"example":{"items":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5c01","text":"Add the fallback over TCP 443 for hotels","done":false,"dueDate":"2026-10-17","overdue":false,"assignee":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Lukas Hofer"},"assignedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a21","name":"Mira Klein"},"item":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a40","number":4711,"kind":"page","title":"VPN access for remote staff","spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a10","spaceKey":"ITOPS","spaceName":"IT Operations"}}],"counts":{"open":1,"done":0,"overdue":0},"nextCursor":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/tasks/{taskId}/status":{"put":{"operationId":"tasks.setStatus","summary":"Check or uncheck a task","description":"Sets a task to done or open without changing the content, so it needs no publication. Editors of the page and the assignee of a published task may do this. Every change records who made it and when.\n\nRequires the permission `task.update` on the task in `taskId`.","tags":["Tasks"],"x-lunedo-permission":{"action":"task.update","resource":"task","parameter":"taskId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"taskId","in":"path","required":true,"description":"ID of the task.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"done":{"type":"boolean","description":"True for done, false for open."}},"required":["done"],"additionalProperties":false,"description":"The new status. Setting the current status again changes nothing."},"example":{"done":true}}}},"responses":{"200":{"description":"The new status.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the task, as in the `id` attribute of the task item."},"done":{"type":"boolean","description":"Whether the task is done."},"changedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the status last changed, or null. ISO 8601 timestamp in UTC."},"changedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, or null when the caller may not see the person.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who changed it last, or null."}},"required":["id","done","changedAt","changedBy"],"additionalProperties":false,"description":"Status of a task."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5c01","done":true,"changedAt":"2026-10-07T09:00:00.000Z","changedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Lukas Hofer"}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/topics/{topicId}":{"get":{"operationId":"meetings.topic","summary":"Get a running topic","description":"Returns status, owner, labels, the timeline of all updates with their meeting and the linked decision, as far as the caller can read them.\n\nRequires the permission `item.view` on the item in `topicId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"topicId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"topicId","in":"path","required":true,"description":"ID of the running topic.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The topic.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the topic."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the topic in the addresses of the app."},"seriesId":{"type":"string","format":"uuid","description":"The series."},"seriesNumber":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the series in the addresses of the app."},"title":{"type":"string","description":"Title."},"status":{"type":"string","description":"Whether the topic is open. New values can be added in later versions; handle unknown values.","x-extensible-enum":["open","closed"]},"outcome":{"anyOf":[{"type":"string","x-extensible-enum":["resolved","decided","dropped"]},{"type":"null"}],"description":"How a closed topic ended. New values can be added in later versions; handle unknown values."},"owner":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, if visible.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who owns the topic."},"labels":{"type":"array","items":{"type":"string"},"description":"Labels."},"oneOff":{"type":"boolean","description":"True for a topic of one meeting only; it closes with that meeting."},"raisedIn":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Meeting ID."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the meeting in the addresses of the app."},"title":{"type":"string","description":"Title of the meeting."},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start of the meeting. ISO 8601 timestamp in UTC."}},"required":["id","number","title","startsAt"],"additionalProperties":false},{"type":"null"}],"description":"The meeting the topic was raised in, if the caller can read it."},"updates":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of updates the caller can read."},"openTasks":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Open tasks written in those updates."},"lastUpdateAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the last update was written. ISO 8601 timestamp in UTC."},"lastUpdateText":{"description":"Text of the last update that is not empty, in one line, or null when there is none.","type":["string","null"]},"createdAt":{"type":"string","format":"date-time","description":"When the topic was raised. ISO 8601 timestamp in UTC."},"closedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the topic was closed. ISO 8601 timestamp in UTC."},"decisionId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The decision that closed the topic."},"spaceId":{"type":"string","format":"uuid","description":"Space of the topic."},"seriesTitle":{"type":"string","description":"Name of the series."},"timeline":{"type":"array","items":{"type":"object","properties":{"meetingId":{"type":"string","format":"uuid","description":"Meeting the update was written in."},"meetingNumber":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of that meeting in the addresses of the app."},"meetingTitle":{"type":"string","description":"Title of that meeting."},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start of that meeting. ISO 8601 timestamp in UTC."},"content":{"type":"array","items":{"$ref":"#/components/schemas/Schema113ae44d8375"},"description":"The update as blocks of the editor schema."},"updatedAt":{"type":"string","format":"date-time","description":"When the update was last changed. ISO 8601 timestamp in UTC."}},"required":["meetingId","meetingNumber","meetingTitle","startsAt","content","updatedAt"],"additionalProperties":false,"description":"An update."},"description":"All updates the caller can read, oldest first. Skipped meetings are left out."},"decision":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Decision ID."},"itemId":{"type":"string","format":"uuid","description":"Page that holds the decision."},"itemNumber":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of that page in the addresses of the app."},"itemTitle":{"type":"string","description":"Title of that page."},"statement":{"type":"array","items":{"$ref":"#/components/schemas/Schemafbc378f59d82"},"description":"The statement as blocks of the editor schema."},"text":{"type":"string","description":"The statement as plain text."}},"required":["id","itemId","itemNumber","itemTitle","statement","text"],"additionalProperties":false},{"type":"null"}],"description":"The decision that closed the topic, if the caller can read it."}},"required":["id","number","seriesId","seriesNumber","title","status","outcome","owner","labels","oneOff","raisedIn","updates","openTasks","lastUpdateAt","lastUpdateText","createdAt","closedAt","decisionId","spaceId","seriesTitle","timeline","decision"],"additionalProperties":false,"description":"A running topic with its history."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6b00","number":1052,"seriesId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a00","seriesNumber":1050,"title":"Positions in AD","status":"open","outcome":null,"owner":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"labels":["directory"],"oneOff":false,"raisedIn":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a10","number":1051,"title":"Jour fixe IT · 12 Oct 2026","startsAt":"2026-10-12T07:30:00.000Z"},"updates":3,"openTasks":1,"lastUpdateAt":"2026-10-05T08:30:00.000Z","lastUpdateText":"Positions stay in AD; the sync runs nightly.","createdAt":"2026-09-21T08:00:00.000Z","closedAt":null,"decisionId":null,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a00","seriesTitle":"Jour fixe IT","timeline":[],"decision":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"patch":{"operationId":"meetings.updateTopic","summary":"Change a running topic","description":"Changes title, owner or labels.\n\nRequires the permission `item.edit` on the item in `topicId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"topicId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"topicId","in":"path","required":true,"description":"ID of the running topic.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"description":"New title.","type":"string","maxLength":510},"ownerId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"New owner, or null for none."},"labels":{"description":"All labels.","maxItems":20,"type":"array","items":{"type":"string","maxLength":200}}},"additionalProperties":false,"description":"Changes to a topic."},"example":{"ownerId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20"}}}},"responses":{"200":{"description":"The topic.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the topic."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the topic in the addresses of the app."},"seriesId":{"type":"string","format":"uuid","description":"The series."},"seriesNumber":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the series in the addresses of the app."},"title":{"type":"string","description":"Title."},"status":{"type":"string","description":"Whether the topic is open. New values can be added in later versions; handle unknown values.","x-extensible-enum":["open","closed"]},"outcome":{"anyOf":[{"type":"string","x-extensible-enum":["resolved","decided","dropped"]},{"type":"null"}],"description":"How a closed topic ended. New values can be added in later versions; handle unknown values."},"owner":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Account ID."},"name":{"description":"Name, if visible.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"Who owns the topic."},"labels":{"type":"array","items":{"type":"string"},"description":"Labels."},"oneOff":{"type":"boolean","description":"True for a topic of one meeting only; it closes with that meeting."},"raisedIn":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Meeting ID."},"number":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of the meeting in the addresses of the app."},"title":{"type":"string","description":"Title of the meeting."},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start of the meeting. ISO 8601 timestamp in UTC."}},"required":["id","number","title","startsAt"],"additionalProperties":false},{"type":"null"}],"description":"The meeting the topic was raised in, if the caller can read it."},"updates":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of updates the caller can read."},"openTasks":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Open tasks written in those updates."},"lastUpdateAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the last update was written. ISO 8601 timestamp in UTC."},"lastUpdateText":{"description":"Text of the last update that is not empty, in one line, or null when there is none.","type":["string","null"]},"createdAt":{"type":"string","format":"date-time","description":"When the topic was raised. ISO 8601 timestamp in UTC."},"closedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the topic was closed. ISO 8601 timestamp in UTC."},"decisionId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The decision that closed the topic."},"spaceId":{"type":"string","format":"uuid","description":"Space of the topic."},"seriesTitle":{"type":"string","description":"Name of the series."},"timeline":{"type":"array","items":{"type":"object","properties":{"meetingId":{"type":"string","format":"uuid","description":"Meeting the update was written in."},"meetingNumber":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of that meeting in the addresses of the app."},"meetingTitle":{"type":"string","description":"Title of that meeting."},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Start of that meeting. ISO 8601 timestamp in UTC."},"content":{"type":"array","items":{"$ref":"#/components/schemas/Schema113ae44d8375"},"description":"The update as blocks of the editor schema."},"updatedAt":{"type":"string","format":"date-time","description":"When the update was last changed. ISO 8601 timestamp in UTC."}},"required":["meetingId","meetingNumber","meetingTitle","startsAt","content","updatedAt"],"additionalProperties":false,"description":"An update."},"description":"All updates the caller can read, oldest first. Skipped meetings are left out."},"decision":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Decision ID."},"itemId":{"type":"string","format":"uuid","description":"Page that holds the decision."},"itemNumber":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Number of that page in the addresses of the app."},"itemTitle":{"type":"string","description":"Title of that page."},"statement":{"type":"array","items":{"$ref":"#/components/schemas/Schemafbc378f59d82"},"description":"The statement as blocks of the editor schema."},"text":{"type":"string","description":"The statement as plain text."}},"required":["id","itemId","itemNumber","itemTitle","statement","text"],"additionalProperties":false},{"type":"null"}],"description":"The decision that closed the topic, if the caller can read it."}},"required":["id","number","seriesId","seriesNumber","title","status","outcome","owner","labels","oneOff","raisedIn","updates","openTasks","lastUpdateAt","lastUpdateText","createdAt","closedAt","decisionId","spaceId","seriesTitle","timeline","decision"],"additionalProperties":false,"description":"A running topic with its history."},"example":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6b00","number":1052,"seriesId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a00","seriesNumber":1050,"title":"Positions in AD","status":"open","outcome":null,"owner":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"labels":["directory"],"oneOff":false,"raisedIn":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a10","number":1051,"title":"Jour fixe IT · 12 Oct 2026","startsAt":"2026-10-12T07:30:00.000Z"},"updates":3,"openTasks":1,"lastUpdateAt":"2026-10-05T08:30:00.000Z","lastUpdateText":"Positions stay in AD; the sync runs nightly.","createdAt":"2026-09-21T08:00:00.000Z","closedAt":null,"decisionId":null,"spaceId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a00","seriesTitle":"Jour fixe IT","timeline":[],"decision":null}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidLabel`: The label is not valid. `invalidMember`: The person cannot take part. `invalidTitle`: The title is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidLabel":{"value":{"type":"urn:lunedo:problem:invalidLabel","title":"The label is not valid","status":400,"code":"invalidLabel"}},"invalidMember":{"value":{"type":"urn:lunedo:problem:invalidMember","title":"The person cannot take part","status":400,"code":"invalidMember"}},"invalidTitle":{"value":{"type":"urn:lunedo:problem:invalidTitle","title":"The title is not valid","status":400,"code":"invalidTitle"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`seriesEnded`: The meeting series has ended. `tooManyLabels`: The page has too many labels.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"seriesEnded":{"value":{"type":"urn:lunedo:problem:seriesEnded","title":"The meeting series has ended","status":409,"code":"seriesEnded"}},"tooManyLabels":{"value":{"type":"urn:lunedo:problem:tooManyLabels","title":"The page has too many labels","status":409,"code":"tooManyLabels"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/topics/{topicId}/close":{"post":{"operationId":"meetings.closeTopic","summary":"Close a running topic","description":"Closes the topic as resolved or dropped. It leaves later meetings; its history stays.\n\nRequires the permission `item.edit` on the item in `topicId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"topicId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"topicId","in":"path","required":true,"description":"ID of the running topic.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"outcome":{"type":"string","enum":["resolved","dropped"],"description":"How the topic ended. Use the decision endpoint for `decided`."},"meetingId":{"type":"string","format":"uuid","description":"Meeting in which it was closed; the current meeting when left out."}},"required":["outcome"],"additionalProperties":false,"description":"Closing a topic. It no longer appears in later meetings; its history stays."},"example":{"outcome":"resolved"}}}},"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`seriesEnded`: The meeting series has ended. `topicClosed`: The topic is closed already.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"seriesEnded":{"value":{"type":"urn:lunedo:problem:seriesEnded","title":"The meeting series has ended","status":409,"code":"seriesEnded"}},"topicClosed":{"value":{"type":"urn:lunedo:problem:topicClosed","title":"The topic is closed already","status":409,"code":"topicClosed"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/topics/{topicId}/decision":{"post":{"operationId":"meetings.decide","summary":"Close a running topic as a decision","description":"Inserts a decision block linked to the topic into the current meeting, closes the topic with outcome `decided` and links both. The topic keeps its history.\n\nRequires the permission `item.edit` on the item in `topicId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"topicId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"topicId","in":"path","required":true,"description":"ID of the running topic.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"statement":{"default":"","description":"The decision, up to 2000 characters; it can be completed in the page.","type":"string","maxLength":4000},"meetingId":{"type":"string","format":"uuid","description":"Meeting to record the decision in; the current meeting when left out."}},"additionalProperties":false,"description":"Closing a topic as a decision."},"example":{"statement":"Positions are kept in AD and synchronized nightly."}}}},"responses":{"200":{"description":"The decision and the meeting it was recorded in.","content":{"application/json":{"schema":{"type":"object","properties":{"decisionId":{"type":"string","format":"uuid","description":"The new decision."},"meetingId":{"type":"string","format":"uuid","description":"The meeting it is in."}},"required":["decisionId","meetingId"],"additionalProperties":false,"description":"The result."},"example":{"decisionId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6c00","meetingId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f6a10"}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid. `invalidStatement`: The decision is too long.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}},"invalidStatement":{"value":{"type":"urn:lunedo:problem:invalidStatement","title":"The decision is too long","status":400,"code":"invalidStatement"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed. `meetingNotEditable`: The meeting notes cannot be edited.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}},"meetingNotEditable":{"value":{"type":"urn:lunedo:problem:meetingNotEditable","title":"The meeting notes cannot be edited","status":403,"code":"meetingNotEditable"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`seriesEnded`: The meeting series has ended. `topicClosed`: The topic is closed already.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"seriesEnded":{"value":{"type":"urn:lunedo:problem:seriesEnded","title":"The meeting series has ended","status":409,"code":"seriesEnded"}},"topicClosed":{"value":{"type":"urn:lunedo:problem:topicClosed","title":"The topic is closed already","status":409,"code":"topicClosed"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/topics/{topicId}/reopen":{"post":{"operationId":"meetings.reopenTopic","summary":"Reopen a running topic","description":"Opens a closed topic again and adds it to the upcoming meeting.\n\nRequires the permission `item.edit` on the item in `topicId`.","tags":["Meetings"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"topicId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"topicId","in":"path","required":true,"description":"ID of the running topic.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The response has no body."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"409":{"description":"`seriesEnded`: The meeting series has ended.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"seriesEnded":{"value":{"type":"urn:lunedo:problem:seriesEnded","title":"The meeting series has ended","status":409,"code":"seriesEnded"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}},"/api/v1/whiteboards/{itemId}/preview":{"get":{"operationId":"whiteboards.preview","summary":"Get the image of a whiteboard","description":"Sends the SVG image of the current state or of a version. Lunedo shows it in the page tree, in search results and in links. Answers 404 when no image was stored yet.\n\nRequires the permission `item.view` on the item in `itemId`.","tags":["Whiteboards"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the whiteboard.","schema":{"type":"string","format":"uuid"}},{"name":"version","in":"query","required":false,"description":"Number of the version. Default: the current state.","schema":{"type":"integer","minimum":1,"maximum":9007199254740991}}],"responses":{"200":{"description":"The image as SVG, sanitized when it was stored. It is sent with `Content-Security-Policy: sandbox` and `X-Content-Type-Options: nosniff`.","content":{"image/svg+xml":{"schema":{"type":"string"},"example":""}}},"206":{"description":"Part of the file, for a request with a `Range` header.","content":{"image/svg+xml":{"schema":{"type":"string"},"example":""}}},"304":{"description":"Not modified: the file matches the `If-None-Match` header."},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}},"put":{"operationId":"whiteboards.storePreview","summary":"Store the image of a whiteboard","description":"Stores the SVG image of a saved state. The web client creates it after its changes were saved. An image of an older state than the stored one is ignored. Versions of the same state get the image too.\n\nRequires the permission `item.edit` on the item in `itemId`.","tags":["Whiteboards"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the whiteboard.","schema":{"type":"string","format":"uuid"}},{"name":"revision","in":"query","required":true,"description":"The stored state the image shows, as reported by the collaboration server after saving.","schema":{"type":"integer","minimum":1,"maximum":9007199254740991}}],"requestBody":{"required":true,"description":"The SVG image, up to 5 MB. Scripts, links, external resources and foreign content are removed.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"Whether the image was kept.","content":{"application/json":{"schema":{"type":"object","properties":{"kept":{"type":"boolean","description":"False when a newer image exists already."}},"required":["kept"],"additionalProperties":false,"description":"The result."},"example":{"kept":true}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidDrawingImage`: The image of the drawing is not a valid SVG image. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidDrawingImage":{"value":{"type":"urn:lunedo:problem:invalidDrawingImage","title":"The image of the drawing is not a valid SVG image","status":400,"code":"invalidDrawingImage"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"408":{"description":"`uploadTimeout`: The upload took too long.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"uploadTimeout":{"value":{"type":"urn:lunedo:problem:uploadTimeout","title":"The upload took too long","status":408,"code":"uploadTimeout"}}}}}},"409":{"description":"`revisionNotStored`: The whiteboard has not been saved in this state yet.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"revisionNotStored":{"value":{"type":"urn:lunedo:problem:revisionNotStored","title":"The whiteboard has not been saved in this state yet","status":409,"code":"revisionNotStored"}}}}}},"413":{"description":"`fileTooLarge`: The file is larger than allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"fileTooLarge":{"value":{"type":"urn:lunedo:problem:fileTooLarge","title":"The file is larger than allowed","status":413,"code":"fileTooLarge"}}}}}},"415":{"description":"`unsupportedMediaType`: The request body has an unsupported type.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unsupportedMediaType":{"value":{"type":"urn:lunedo:problem:unsupportedMediaType","title":"The request body has an unsupported type","status":415,"code":"unsupportedMediaType"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`busy`: The server is busy. `maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"busy":{"value":{"type":"urn:lunedo:problem:busy","title":"The server is busy","status":503,"code":"busy"}},"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}},"507":{"description":"`storageFull`: Storage is almost full.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"storageFull":{"value":{"type":"urn:lunedo:problem:storageFull","title":"Storage is almost full","status":507,"code":"storageFull"}}}}}}}}},"/api/v1/whiteboards/{itemId}/reference":{"get":{"operationId":"whiteboards.reference","summary":"Get a whiteboard for a whiteboard block","description":"Returns the title, the address and whether an image exists, for showing the whiteboard in a page. Answers 404 for whiteboards the caller cannot see, so a block shows nothing to them.\n\nRequires the permission `item.view` on the item in `itemId`.","tags":["Whiteboards"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the whiteboard.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The whiteboard as a block shows it.","content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"ID of the whiteboard."},"title":{"type":"string","description":"Title of the whiteboard."},"href":{"type":"string","description":"Address of the whiteboard in Lunedo."},"preview":{"type":"boolean","description":"Whether an image of the whiteboard exists."}},"required":["itemId","title","href","preview"],"additionalProperties":false,"description":"A whiteboard as a whiteboard block in a page shows it."},"example":{"itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a21","title":"Network 2027","href":"/spaces/IT/whiteboards/1021/network-2027","preview":true}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/whiteboards/{itemId}/scene":{"get":{"operationId":"whiteboards.scene","summary":"Get the content of a whiteboard","description":"Returns the stored scene. People who edit the board together use the collaboration server with the document name `whiteboard:<ID>`; it stores the scene about a second after each change.\n\nRequires the permission `item.view` on the item in `itemId`.","tags":["Whiteboards"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the whiteboard.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The whiteboard.","content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid","description":"ID of the whiteboard."},"scene":{"description":"The scene: `elements` (Excalidraw elements of the types rectangle, diamond, ellipse, arrow, line, freedraw, text, image and frame, ordered by their `index`), `files` (images by file ID, each the `attachmentId` of an attachment of the item and its `mimeType`) and `settings` (`viewBackgroundColor`).","$ref":"#/components/schemas/Schema113ae44d8375"},"revision":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the stored state."},"updatedAt":{"type":"string","format":"date-time","description":"When the scene was last stored. ISO 8601 timestamp in UTC."},"updatedBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when the account no longer exists.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who changed it last, or null."},"preview":{"type":"boolean","description":"Whether an image of the current state exists."}},"required":["itemId","scene","revision","updatedAt","updatedBy","preview"],"additionalProperties":false,"description":"The current content of a whiteboard."},"example":{"itemId":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a21","scene":{"elements":[],"files":{},"settings":{"viewBackgroundColor":null}},"revision":12,"updatedAt":"2026-10-16T09:12:00.000Z","updatedBy":{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"},"preview":true}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/whiteboards/{itemId}/versions":{"get":{"operationId":"whiteboards.versions","summary":"List the versions of a whiteboard","description":"Lists all versions, newest first. A version is kept when the last person leaves the board and after it was idle for the time set for live pages.\n\nRequires the permission `item.view` on the item in `itemId`.","tags":["Whiteboards"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the whiteboard.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Versions.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"number":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the version, counting from 1."},"title":{"type":"string","description":"Title of the whiteboard in this version."},"reason":{"type":"string","description":"Why the version exists: `session` (an editing session ended or the board was idle), `restored` (an older version was restored) or `copied` (the board was created as a copy of `copiedFrom`). New values can be added in later versions; handle unknown values.","x-extensible-enum":["published","session","restored","modeChanged","imported","importedNotApplied","copied"]},"restoredFrom":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The restored version, or null."},"copiedFrom":{"anyOf":[{"type":"object","properties":{"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The source, or null when the caller cannot read it or it was deleted permanently."},"title":{"description":"Title of the source when it was copied, or null when the caller cannot read the source.","type":["string","null"]},"path":{"description":"Path of the source in the web interface, or null when the caller cannot read the source.","type":["string","null"]}},"required":["itemId","title","path"],"additionalProperties":false},{"type":"null"}],"description":"Where a copy came from, for the first version of a copy; null otherwise."},"createdAt":{"type":"string","format":"date-time","description":"When the version was created. ISO 8601 timestamp in UTC."},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when the account no longer exists.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who restored or copied, or null for versions of editing sessions."},"contributors":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when the account no longer exists.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"Everyone who changed the board since the previous version."},"preview":{"type":"boolean","description":"Whether an image of this version exists."}},"required":["number","title","reason","restoredFrom","copiedFrom","createdAt","createdBy","contributors","preview"],"additionalProperties":false,"description":"A version of a whiteboard."},"description":"Versions, newest first."},"example":[{"number":3,"title":"Network redesign 2027","reason":"session","restoredFrom":null,"copiedFrom":null,"createdAt":"2026-10-16T09:12:00.000Z","createdBy":null,"contributors":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"}],"preview":true}]}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/whiteboards/{itemId}/versions/{number}":{"get":{"operationId":"whiteboards.version","summary":"Get a version of a whiteboard","description":"Returns a version with its scene.\n\nRequires the permission `item.view` on the item in `itemId`.","tags":["Whiteboards"],"x-lunedo-permission":{"action":"item.view","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the whiteboard.","schema":{"type":"string","format":"uuid"}},{"name":"number","in":"path","required":true,"description":"Number of the version.","schema":{"type":"integer","minimum":1,"maximum":2147483647}}],"responses":{"200":{"description":"The version.","content":{"application/json":{"schema":{"type":"object","properties":{"number":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of the version, counting from 1."},"title":{"type":"string","description":"Title of the whiteboard in this version."},"reason":{"type":"string","description":"Why the version exists: `session` (an editing session ended or the board was idle), `restored` (an older version was restored) or `copied` (the board was created as a copy of `copiedFrom`). New values can be added in later versions; handle unknown values.","x-extensible-enum":["published","session","restored","modeChanged","imported","importedNotApplied","copied"]},"restoredFrom":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The restored version, or null."},"copiedFrom":{"anyOf":[{"type":"object","properties":{"itemId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"The source, or null when the caller cannot read it or it was deleted permanently."},"title":{"description":"Title of the source when it was copied, or null when the caller cannot read the source.","type":["string","null"]},"path":{"description":"Path of the source in the web interface, or null when the caller cannot read the source.","type":["string","null"]}},"required":["itemId","title","path"],"additionalProperties":false},{"type":"null"}],"description":"Where a copy came from, for the first version of a copy; null otherwise."},"createdAt":{"type":"string","format":"date-time","description":"When the version was created. ISO 8601 timestamp in UTC."},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when the account no longer exists.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},{"type":"null"}],"description":"Who restored or copied, or null for versions of editing sessions."},"contributors":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"description":"Name of the person, or null when the account no longer exists.","type":["string","null"]}},"required":["id","name"],"additionalProperties":false,"description":"A person."},"description":"Everyone who changed the board since the previous version."},"preview":{"type":"boolean","description":"Whether an image of this version exists."},"scene":{"description":"The scene: `elements` (Excalidraw elements of the types rectangle, diamond, ellipse, arrow, line, freedraw, text, image and frame, ordered by their `index`), `files` (images by file ID, each the `attachmentId` of an attachment of the item and its `mimeType`) and `settings` (`viewBackgroundColor`).","$ref":"#/components/schemas/Schema113ae44d8375"}},"required":["number","title","reason","restoredFrom","copiedFrom","createdAt","createdBy","contributors","preview","scene"],"additionalProperties":false,"description":"A version with its scene."},"example":{"number":3,"title":"Network redesign 2027","reason":"session","restoredFrom":null,"copiedFrom":null,"createdAt":"2026-10-16T09:12:00.000Z","createdBy":null,"contributors":[{"id":"01929b1e-7c3a-7d2e-9f4b-3c2d1e0f5a20","name":"Anna Berger"}],"preview":true,"scene":{"elements":[],"files":{},"settings":{"viewBackgroundColor":null}}}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}}}}},"/api/v1/whiteboards/{itemId}/versions/{number}/restore":{"post":{"operationId":"whiteboards.restore","summary":"Restore a version of a whiteboard","description":"The version becomes the current content at once, also for people editing the board, and a new version is created. History is never rewritten.\n\nRequires the permission `item.edit` on the item in `itemId`.","tags":["Whiteboards"],"x-lunedo-permission":{"action":"item.edit","resource":"item","parameter":"itemId"},"security":[{"bearerAuth":[]},{"sessionCookie":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"description":"ID of the whiteboard.","schema":{"type":"string","format":"uuid"}},{"name":"number","in":"path","required":true,"description":"Number of the version.","schema":{"type":"integer","minimum":1,"maximum":2147483647}}],"responses":{"200":{"description":"The new version.","content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The new version."}},"required":["version"],"additionalProperties":false,"description":"The result."},"example":{"version":4}}}},"400":{"description":"`ambiguousCredentials`: The request carries both a session and an API token. `invalidInput`: The request is not valid.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"ambiguousCredentials":{"value":{"type":"urn:lunedo:problem:ambiguousCredentials","title":"The request carries both a session and an API token","status":400,"code":"ambiguousCredentials"}},"invalidInput":{"value":{"type":"urn:lunedo:problem:invalidInput","title":"The request is not valid","status":400,"code":"invalidInput"}}}}}},"401":{"description":"`invalidApiToken`: The API token is not valid. `notSignedIn`: Sign in or send an API token.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalidApiToken":{"value":{"type":"urn:lunedo:problem:invalidApiToken","title":"The API token is not valid","status":401,"code":"invalidApiToken"}},"notSignedIn":{"value":{"type":"urn:lunedo:problem:notSignedIn","title":"Sign in or send an API token","status":401,"code":"notSignedIn"}}}}}},"403":{"description":"`csrfRejected`: The request failed the cross-site request check. `forbidden`: Not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"csrfRejected":{"value":{"type":"urn:lunedo:problem:csrfRejected","title":"The request failed the cross-site request check","status":403,"code":"csrfRejected"}},"forbidden":{"value":{"type":"urn:lunedo:problem:forbidden","title":"Not allowed","status":403,"code":"forbidden"}}}}}},"404":{"description":"`notFound`: Not found. `versionNotFound`: The version does not exist.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"notFound":{"value":{"type":"urn:lunedo:problem:notFound","title":"Not found","status":404,"code":"notFound"}},"versionNotFound":{"value":{"type":"urn:lunedo:problem:versionNotFound","title":"The version does not exist","status":404,"code":"versionNotFound"}}}}}},"429":{"description":"`rateLimited`: Too many requests.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"rateLimited":{"value":{"type":"urn:lunedo:problem:rateLimited","title":"Too many requests","status":429,"code":"rateLimited"}}}}}},"503":{"description":"`maintenanceMode`: The instance is in maintenance mode.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"maintenanceMode":{"value":{"type":"urn:lunedo:problem:maintenanceMode","title":"The instance is in maintenance mode","status":503,"code":"maintenanceMode"}}}}}}}}}},"components":{"schemas":{"Problem":{"type":"object","properties":{"type":{"type":"string","description":"Stable identifier of the error kind. Clients branch on this value."},"title":{"type":"string","description":"Short summary of the error kind. It does not change between occurrences."},"status":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"HTTP status code of the response."},"detail":{"description":"Explanation of this occurrence, for people.","type":"string"},"code":{"type":"string","description":"The last part of `type`, for clients that prefer a short key."},"fields":{"description":"Invalid fields, for `invalidInput`, `invalidStorageSettings`, `invalidBackupSettings` and the codes about the address of a chat channel.","type":"array","items":{"type":"string","description":"Path of an invalid field, with dots between levels."}},"denials":{"description":"Why the request was not allowed, for `forbidden`.","type":"array","items":{"type":"string","description":"Reason code of the authorization service."}},"retryAfterSeconds":{"description":"Seconds to wait before retrying, for `rateLimited`, `locked` and `busy`.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"problem":{"description":"Which password rule failed, for `passwordPolicy`; why the address of a chat channel was refused, for `invalidChatAddress`; which storage setting was refused (`invalidThresholds`, `invalidS3Limit`, `invalidContacts` or `invalidTeamsWebhook`), for `invalidStorageSettings`; which backup setting was refused, for `invalidBackupSettings`; whether a `backup` or a `testRestore` is running, for `backupRunning`; why the backup target could not be used (a failure of **Test connection**, such as `notFound` or `credentials`, or `missingSecret`), for `backupTargetFailed`.","type":"string"},"step":{"description":"What Lunedo was doing with the backup target when it failed, for `backupTargetFailed`.","type":"string","enum":["write","read","delete","list"]},"refusal":{"description":"What the full storage refuses, for `storageFull`: an `upload`, or a large write such as an import.","type":"string","enum":["upload","largeWrite"]},"minLength":{"description":"Minimum password length, for `passwordPolicy`.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"lockedBy":{"description":"Level that locked the setting, for `settingLocked`.","type":"string"},"minimum":{"description":"Lowest allowed value, for `settingBelowMinimum`.","type":"number"},"maximum":{"description":"Highest allowed value, for `settingAboveMaximum`.","anyOf":[{"type":"number"},{"type":"string","const":"unlimited"}]},"maxLifetimeDays":{"description":"Maximum lifetime of API tokens in days, for `expiryRequired` and `expiryTooLate`.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"domains":{"description":"Domains that belong to another identity provider, for `domainInUse`.","type":"array","items":{"type":"string","description":"A domain."}},"instanceUrl":{"description":"The current address of the instance, for `instanceMoved`.","type":"string"},"providerId":{"description":"ID of the identity provider that manages the account, for `managedAccount` and `managedDomain`.","type":"string"},"providerName":{"description":"Name of the identity provider that manages the account, for `managedAccount` and `managedDomain`.","type":"string"},"accounts":{"description":"Number of accounts still linked to the identity provider, for `providerHasAccounts`.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"maxBytes":{"description":"Largest allowed file size in bytes, for `fileTooLarge` and `uploadTooLarge`; storage limit of the organization's imports, for `organizationImportLimit`.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"usedBytes":{"description":"Bytes the organization's imports use already, for `organizationImportLimit`.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"missing":{"description":"Number of parts still missing, for `uploadIncomplete`.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"uncoveredPages":{"description":"Number of pages below that your own role does not cover, for `shareBeyondOwnAccess`.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"maxDays":{"description":"Longest allowed lifetime of a link for anyone in days, for `expiryTooLate`.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"pages":{"description":"Number of pages that give access to groups or through broad links, for `confidentialSharing`; number of pages that would lose the status, for `statusInUse`; number of pages the caller cannot open, for `hiddenContent`.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"sections":{"description":"Required sections that are empty or missing, for `requiredSectionsEmpty`.","type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Key of the section."},"title":{"type":"string","description":"Heading of the section."}},"required":["key","title"],"additionalProperties":false,"description":"A required section."}},"articles":{"description":"Number of articles more people could read, for `audienceWidening` and `categoryVisibilityWidening`.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"translations":{"description":"Number of translations into the language, for `defaultLanguageTranslated`.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"translationId":{"type":"string","format":"uuid","description":"The existing translation, for `translationExists`."},"light":{"description":"Check of the light mode color, for `brandContrast`.","type":"object","properties":{"color":{"type":"string","description":"The checked color."},"passes":{"type":"boolean","description":"Whether it reaches the contrast WCAG AA asks for."},"onBackground":{"type":"number","description":"Contrast of the color as text on the background."},"onBrand":{"type":"number","description":"Contrast of text on the color."},"proposal":{"description":"The nearest shade that passes, or null when none exists.","type":["string","null"]}},"required":["color","passes","onBackground","onBrand","proposal"],"additionalProperties":false},"dark":{"description":"Check of the dark mode color, for `brandContrast`.","type":"object","properties":{"color":{"type":"string","description":"The checked color."},"passes":{"type":"boolean","description":"Whether it reaches the contrast WCAG AA asks for."},"onBackground":{"type":"number","description":"Contrast of the color as text on the background."},"onBrand":{"type":"number","description":"Contrast of text on the color."},"proposal":{"description":"The nearest shade that passes, or null when none exists.","type":["string","null"]}},"required":["color","passes","onBackground","onBrand","proposal"],"additionalProperties":false},"impact":{"description":"Who gains and who loses access, with the confirmation to send, for `moveChangesAccess`.","type":"object","properties":{"gaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who get access."},"losing":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who lose access."},"raised":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role rises."},"lowered":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role drops."},"unlisted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of affected people the caller may not see; they are counted but not listed."},"truncated":{"type":"boolean","description":"Whether `changes` lists only the first 100 people."},"changes":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."},"before":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role before the change, or null for no access."},"after":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role after the change, or null for no access."}},"required":["accountId","name","before","after"],"additionalProperties":false,"description":"How the access of one person changes."},"description":"People whose access changes, ordered by name."},"leavesConfidential":{"type":"boolean","description":"True when the content leaves a confidential space and loses its protection."},"confirmation":{"description":"Send this with the move to confirm exactly this change, or null when access does not change. Valid for one hour.","type":["string","null"]}},"required":["gaining","losing","raised","lowered","unlisted","truncated","changes","leavesConfidential","confirmation"],"additionalProperties":false},"copyImpact":{"description":"Who could read the copy but not the source, with the confirmation to send, for `copyChangesAccess`.","type":"object","properties":{"gaining":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who get access."},"losing":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people who lose access."},"raised":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role rises."},"lowered":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of people whose role drops."},"unlisted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of affected people the caller may not see; they are counted but not listed."},"truncated":{"type":"boolean","description":"Whether `changes` lists only the first 100 people."},"changes":{"type":"array","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","description":"ID of the account."},"name":{"type":"string","description":"Name of the person."},"before":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role before the change, or null for no access."},"after":{"anyOf":[{"type":"string","enum":["reader","commenter","editor","admin"],"description":"Space role: `reader` reads, `commenter` also comments, `editor` also creates, edits and moves content, `admin` also manages the space and its permissions."},{"type":"null"}],"description":"Role after the change, or null for no access."}},"required":["accountId","name","before","after"],"additionalProperties":false,"description":"How the access of one person changes."},"description":"People whose access changes, ordered by name."},"leavesConfidential":{"type":"boolean","description":"True when the copy leaves a confidential space and is not protected by it."},"widerAccess":{"type":"boolean","description":"True when people can read the copy who cannot read the source; the copy then needs the confirmation."},"confirmation":{"description":"Send this with the copy to confirm exactly this access, or null when nobody gains access. Valid for one hour.","type":["string","null"]},"items":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of items the copy creates."},"hidden":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of items below that are left out because the caller cannot read them."},"skipped":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of items below that are left out because they cannot be copied."},"background":{"type":"boolean","description":"True when the copy is large and runs in the background."}},"required":["gaining","losing","raised","lowered","unlisted","truncated","changes","leavesConfidential","widerAccess","confirmation","items","hidden","skipped","background"],"additionalProperties":false},"formerParent":{"description":"The former parent page in the trash, for `restrictedParentInTrash`; null when the caller may not view it.","anyOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"ID of the former parent page."},"title":{"type":"string","description":"Title of the former parent page."}},"required":["id","title"],"additionalProperties":false},{"type":"null"}]},"parentEntries":{"description":"Number of trash entries of former parent pages the caller can restore together with the content, for `restrictedParentInTrash`; 0 when the caller cannot restore all of them.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"fileVersion":{"description":"Format or editor schema version of the file, for `newerTemplateFormat`.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"supportedVersion":{"description":"Highest format or editor schema version this Lunedo reads, for `newerTemplateFormat`.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"templateIndex":{"description":"Position of the template in the file, counted from 0, for `templateNameTaken`.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"templateProblems":{"description":"What is wrong with the templates of the file, for `invalidTemplatesInFile`.","type":"array","items":{"type":"object","properties":{"place":{"description":"Where in the template, such as `field 3` or `content`.","type":["string","null"]},"message":{"type":"string","description":"Explanation for people, naming the template and the place."}},"required":["place","message"],"additionalProperties":false,"description":"A problem in a template of the file."}},"maintenanceMessage":{"description":"The message of the instance administrators about the maintenance, for `maintenanceMode` and `signInPaused`. Empty when they wrote none.","type":"string"},"problems":{"description":"What is wrong with the document, for `invalidDocument` and `invalidComment`.","type":"array","items":{"type":"object","properties":{"path":{"type":"string","description":"Position in the document, such as `.content[2].content[0]`."},"code":{"type":"string","description":"Kind of problem, such as `unknownNode` or `invalidAttribute`."},"message":{"type":"string","description":"Explanation for people."}},"required":["path","code","message"],"additionalProperties":false,"description":"A problem in the document."}}},"required":["type","title","status","code"],"additionalProperties":false,"description":"Error response following RFC 9457 Problem Details."},"Schema113ae44d8375":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"null"},{"type":"array","items":{"$ref":"#/components/schemas/Schema113ae44d8375"}},{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/components/schemas/Schema113ae44d8375"}}]},"Schema1a810d563c56":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"null"},{"type":"array","items":{"$ref":"#/components/schemas/Schema1a810d563c56"}},{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/components/schemas/Schema1a810d563c56"}}]},"Schema682d67ac39ef":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"null"},{"type":"array","items":{"$ref":"#/components/schemas/Schema682d67ac39ef"}},{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/components/schemas/Schema682d67ac39ef"}}]},"Schemae0c307037cb0":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"null"},{"type":"array","items":{"$ref":"#/components/schemas/Schemae0c307037cb0"}},{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/components/schemas/Schemae0c307037cb0"}}]},"Schemafbc378f59d82":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"null"},{"type":"array","items":{"$ref":"#/components/schemas/Schemafbc378f59d82"}},{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/components/schemas/Schemafbc378f59d82"}}]}},"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An API token starting with `ld_`, sent as `Authorization: Bearer <token>`."},"sessionCookie":{"type":"apiKey","in":"cookie","name":"__Host-lunedo-session","description":"The session of a signed-in user. State-changing requests also need the `X-Lunedo-Request: 1` header."}}}}
