{
  "openapi": "3.1.0",
  "info": {
    "title": "Dew API",
    "version": "1",
    "description": "Send and collect files, manage users and read activity on your Dew server from other systems. Authenticate with a service account token (`dewsa_…`) or a personal token (`dewpt_…`) in the `Authorization: Bearer` header. Every JSON response has `success`; successful responses carry `data`, failed ones `error` and a readable `message`."
  },
  "servers": [
    {
      "url": "https://files.example.com",
      "description": "Your Dew server"
    }
  ],
  "tags": [
    {
      "name": "Files",
      "description": "Upload files, share them through links and download them."
    },
    {
      "name": "Uploads",
      "description": "Resumable uploads in chunks, for large files and several files behind one link."
    },
    {
      "name": "File requests",
      "description": "Ask people to send you files and download what they send."
    },
    {
      "name": "Users",
      "description": "Users, invitations and desktop app sign-ins. Service account tokens only."
    },
    {
      "name": "Groups",
      "description": "Groups, and who is on each domain's access list. Service account tokens only."
    },
    {
      "name": "Settings",
      "description": "Read domain, email, storage and single sign-on settings. Service account tokens only; changing settings is for people only."
    },
    {
      "name": "Activity",
      "description": "What happens to files and file requests on the service account's domains, on every plan."
    },
    {
      "name": "Audit log",
      "description": "The full audit log, for a SIEM. Needs Enterprise."
    },
    {
      "name": "Monitoring",
      "description": "Server health, system logs, access logs, license status and alerts."
    }
  ],
  "components": {
    "securitySchemes": {
      "token": {
        "type": "http",
        "scheme": "bearer",
        "description": "A service account token (`dewsa_…`) or a personal token (`dewpt_…`). The scopes listed on each operation are the permissions the token needs; personal tokens only hold the files and file requests permissions."
      }
    },
    "parameters": {
      "ActAs": {
        "name": "Dew-Act-As",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "format": "email"
        },
        "description": "Service account tokens only: act as this user. They must have one of the service account's domains. What the request creates belongs to them."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "success",
          "error",
          "message"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": false
          },
          "error": {
            "type": "string",
            "description": "The error type, such as `Not Found` or `ScopeMissing`, or on server errors an error code such as `FILE_LIST`."
          },
          "message": {
            "type": "string",
            "description": "A readable explanation."
          },
          "ref": {
            "type": "string",
            "description": "On server errors, a reference to quote to your admin, such as `REF-a3f8b2c1`."
          }
        }
      },
      "Success": {
        "type": "object",
        "required": [
          "success"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "message": {
            "type": "string"
          }
        }
      },
      "FileUploadResult": {
        "type": "object",
        "description": "A delivered file and its shared link.",
        "required": [
          "id",
          "url",
          "formatted_text",
          "filename",
          "filesize"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The file's ID."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The shared link. ZIP archives get a `/p/` link that opens a page listing the files inside; other files get a `/f/` link."
          },
          "formatted_text": {
            "type": "string",
            "description": "The link written out with your admin's link template, which may add the file name, size and expiry date. Dates use the time zone named in an `X-Timezone` request header (such as `Europe/Copenhagen`), or the server's time zone without it."
          },
          "filename": {
            "type": "string",
            "description": "The file's name. For several files, the archive's name, such as `Project files.zip`."
          },
          "filesize": {
            "type": "integer",
            "format": "int64",
            "description": "Size in bytes."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the link expires. Left out when it never expires. New links expire after the number of days your admin sets (30 by default)."
          },
          "generated_password": {
            "type": "string",
            "description": "The link's password, when you asked Dew to generate one (`auto_generate` without a password). This is the only time it is returned."
          }
        }
      },
      "FileInfo": {
        "type": "object",
        "description": "A file you own.",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "size": {
            "type": "integer",
            "format": "int64",
            "description": "Size in bytes."
          },
          "mime_type": {
            "type": "string"
          },
          "owner_id": {
            "type": "string",
            "description": "The ID of the user who owns the file."
          },
          "downloads": {
            "type": "integer",
            "format": "int64",
            "description": "How many times the file was downloaded through its shared link."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "Left out when the link never expires."
          },
          "domain_hostname": {
            "type": "string",
            "description": "The domain the shared link is on."
          }
        }
      },
      "FileListItem": {
        "type": "object",
        "description": "A file and its shared link.",
        "required": [
          "id",
          "name",
          "size",
          "url",
          "formatted_text",
          "downloads",
          "created_at",
          "link_type",
          "domain_hostname",
          "download_receipt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "size": {
            "type": "integer",
            "format": "int64",
            "description": "Size in bytes."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The shared link."
          },
          "formatted_text": {
            "type": "string",
            "description": "The link written out with your admin's link template."
          },
          "downloads": {
            "type": "integer",
            "format": "int64",
            "description": "How many times the file was downloaded through its shared link."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the file was uploaded. Pass it back unchanged as `cursor_ts` to get the next page."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the link expires. Left out when it never expires."
          },
          "max_expiry_at": {
            "type": "string",
            "format": "date-time",
            "description": "The latest expiry date the domain allows for this file. A token can't set a later one."
          },
          "link_type": {
            "type": "string",
            "enum": [
              "public",
              "protected",
              "private",
              "onetime"
            ],
            "description": "Who can open the shared link. See Update link settings."
          },
          "protection_method": {
            "type": "string",
            "enum": [
              "password",
              "sms",
              "email"
            ],
            "description": "Only on `protected` links."
          },
          "domain_hostname": {
            "type": "string",
            "description": "The domain the shared link is on."
          },
          "download_receipt": {
            "type": "boolean",
            "description": "Whether the owner gets an email the first time the file is downloaded."
          }
        }
      },
      "AdminFileListItem": {
        "allOf": [
          {
            "$ref": "#/components/schemas/FileListItem"
          },
          {
            "type": "object",
            "properties": {
              "owner_username": {
                "type": "string",
                "description": "The owner's display name."
              },
              "owner_email": {
                "type": "string",
                "description": "The owner's email address. Empty when a service account owns the file."
              }
            }
          }
        ]
      },
      "LinkEmailRecipient": {
        "type": "object",
        "description": "A person who can open an email-protected link.",
        "required": [
          "id",
          "email",
          "invitation_failed"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "invitation_sent_at": {
            "type": "string",
            "format": "date-time",
            "description": "When their invitation email was sent. Left out until it is."
          },
          "invitation_failed": {
            "type": "boolean",
            "description": "`true` when the invitation email couldn't be sent. Resend invitations with `failed_only=true` to retry."
          }
        }
      },
      "LinkSettings": {
        "type": "object",
        "description": "Who can open a file's shared link. Fields beyond `link_type` depend on the link type.",
        "required": [
          "file_id",
          "link_type"
        ],
        "properties": {
          "file_id": {
            "type": "string"
          },
          "link_type": {
            "type": "string",
            "enum": [
              "public",
              "protected",
              "private",
              "onetime",
              "locked"
            ],
            "description": "`locked` is a file received through a file request: only its owner can download it."
          },
          "protection_method": {
            "type": "string",
            "enum": [
              "password",
              "sms",
              "email"
            ],
            "description": "Only on `protected` links."
          },
          "password_auto_generated": {
            "type": "boolean",
            "description": "Password links: whether the password was generated. The password itself is never returned to a token."
          },
          "phone_number": {
            "type": "string",
            "description": "SMS links: the number codes are sent to, in international format."
          },
          "country_code": {
            "type": "string",
            "description": "SMS links: the ISO 3166-1 alpha-2 country the number was entered for."
          },
          "allowlist_id": {
            "type": "string",
            "description": "Private links: the IP allowlist that may open the link."
          },
          "allowlist_name": {
            "type": "string",
            "description": "Private links: the allowlist's name."
          },
          "email_recipients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LinkEmailRecipient"
            },
            "description": "Email links: the people who can open it."
          },
          "email_message": {
            "type": "string",
            "description": "Email links: the message included in invitations, when one is set."
          },
          "is_bound": {
            "type": "boolean",
            "description": "One-time links: whether someone has started downloading it, which uses the link up."
          },
          "bound_at": {
            "type": "string",
            "format": "date-time",
            "description": "One-time links: when the download started."
          }
        }
      },
      "LinkSettingsUpdate": {
        "type": "object",
        "description": "The new settings for a shared link.",
        "properties": {
          "link_type": {
            "type": "string",
            "enum": [
              "public",
              "protected",
              "private",
              "onetime"
            ],
            "default": "public",
            "description": "`public`: anyone with the link. `protected`: needs a password, a code sent by SMS, or a code sent to an invited email address. `private`: only from IP addresses on an allowlist. `onetime`: works for one download. Left out, the link becomes `public`."
          },
          "protection_method": {
            "type": "string",
            "enum": [
              "password",
              "sms",
              "email"
            ],
            "description": "Required when `link_type` is `protected`."
          },
          "password": {
            "type": "string",
            "description": "Password links: the password. Leave out both `password` and `auto_generate` to keep the current password."
          },
          "auto_generate": {
            "type": "boolean",
            "description": "Password links: generate a password instead. The response returns a generated password once, as `generated_password`."
          },
          "phone_number": {
            "type": "string",
            "description": "SMS links: the full international number, such as `+15551234567`. Spaces, dashes and brackets are allowed."
          },
          "country_code": {
            "type": "string",
            "description": "SMS links: ISO 3166-1 alpha-2 country, such as `US`. Used for display only."
          },
          "allowlist_id": {
            "type": "string",
            "description": "Required for `private` links: an allowlist available on the file's domain."
          },
          "email_recipients": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "email"
              ],
              "properties": {
                "email": {
                  "type": "string",
                  "format": "email"
                }
              }
            },
            "description": "Email links: everyone who should have access. People already on the link keep it and get no new email; new addresses get an invitation; addresses you leave out lose access."
          },
          "email_message": {
            "type": "string",
            "description": "Email links: a message included in invitations sent by this change."
          }
        },
        "example": {
          "link_type": "protected",
          "protection_method": "password",
          "password": "harbor-lantern-42"
        },
        "required": [
          "link_type"
        ]
      },
      "UploadSessionFileInput": {
        "type": "object",
        "description": "A file you are about to upload.",
        "properties": {
          "filename": {
            "type": "string",
            "description": "The file's name, at most 1020 bytes, without text-direction control characters."
          },
          "relative_path": {
            "type": "string",
            "maxLength": 4096,
            "description": "Where the file sits in the archive, such as `2026/photos/IMG_001.jpg`. Use forward slashes; no leading slash, no `.` or `..` parts, no control characters. For `single` uploads, use the file name."
          },
          "size_bytes": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "The file's exact size in bytes."
          },
          "mime_type": {
            "type": "string",
            "description": "The file's type, such as `application/pdf`."
          }
        }
      },
      "UploadLinkProtection": {
        "type": "object",
        "description": "Link settings for a `protected` or `private` link.",
        "properties": {
          "method": {
            "type": "string",
            "enum": [
              "password",
              "sms",
              "email"
            ],
            "description": "Required for `protected` links."
          },
          "password": {
            "type": "string",
            "description": "Password links: the password."
          },
          "auto_generate": {
            "type": "boolean",
            "description": "Password links: generate a password instead. The response returns a generated password once, as `generated_password`."
          },
          "phone_number": {
            "type": "string",
            "description": "SMS links: the full international number, such as `+15551234567`."
          },
          "country_code": {
            "type": "string",
            "description": "SMS links: ISO 3166-1 alpha-2 country, such as `US`. Used for display only."
          },
          "private_list_id": {
            "type": "string",
            "description": "Required for `private` links: an allowlist available on the domain."
          },
          "email_recipients": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "email"
              ],
              "properties": {
                "email": {
                  "type": "string",
                  "format": "email"
                }
              }
            },
            "description": "Email links: the people to invite. Each gets their own invitation email when the upload finishes."
          },
          "email_message": {
            "type": "string",
            "description": "Email links: a message included in the invitations."
          }
        }
      },
      "UploadSessionCreate": {
        "type": "object",
        "required": [
          "session_type",
          "files"
        ],
        "properties": {
          "session_type": {
            "type": "string",
            "enum": [
              "single",
              "multi",
              "folder"
            ],
            "description": "`single`: one file, uploaded as it is. `multi`: several files behind one link. `folder`: like `multi`, keeping the folder structure and empty folders.\n\nFor `multi` and `folder` you upload one ZIP archive that you write yourself. It must be exactly `artifact.size_bytes` long, which it is when you follow this layout:\n\n- Entries in order: the `empty_dirs` names first, as returned, then the files by `entry_index`, each named by its `entry_name`.\n- Every entry stored (no compression), with the UTF-8 name flag set and no extra fields except zip64 ones. No archive comment.\n- A file entry is a local header (30 bytes plus the name) with the data descriptor flag set and CRC and sizes zero, then the file's bytes, then a data descriptor with its signature: 16 bytes, or 24 bytes when the file is 4 GiB - 1 bytes or larger. A folder entry is a local header only, with a name ending in `/`.\n- An entry uses zip64 when its size or the offset of its local header reaches 4 GiB - 1. Its central directory record then carries the 28-byte zip64 extra field with both sizes and the offset, and both 32-bit size fields are `0xFFFFFFFF`.\n- Add the zip64 end of central directory record and locator when there are 65,535 entries or more, or the central directory's size or offset reaches 4 GiB - 1.\n\nFinish an upload checks the archive's central directory: exactly the files you listed (minus any you skip), stored, at their declared sizes."
          },
          "files": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UploadSessionFileInput"
            },
            "description": "The files to upload, in archive order. A `single` upload takes exactly one. A `folder` upload may send none when `empty_dirs` lists at least one folder. Requests are capped at 4 MiB; send more files with Add files."
          },
          "link_type": {
            "type": "string",
            "enum": [
              "public",
              "protected",
              "private",
              "onetime"
            ],
            "description": "Who can open the shared link: `public` (anyone with the link), `protected` (password, SMS code or invited email addresses, set in `protection`), `private` (IP allowlist, set in `protection`) or `onetime` (one download).",
            "default": "public"
          },
          "protection": {
            "$ref": "#/components/schemas/UploadLinkProtection"
          },
          "domain": {
            "type": "string",
            "description": "The domain for the shared link. It must be active and one you may use. Defaults to the domain you call the API on."
          },
          "folder_name": {
            "type": "string",
            "description": "`multi` and `folder`: the archive's name, without `.zip`, at most 1020 bytes. Defaults to `archive-` plus the date and time."
          },
          "empty_dirs": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "`folder`: empty folders to keep, such as `2026/raw`."
          }
        },
        "example": {
          "session_type": "multi",
          "folder_name": "Project files",
          "files": [
            {
              "filename": "brief.pdf",
              "relative_path": "brief.pdf",
              "size_bytes": 482133,
              "mime_type": "application/pdf"
            },
            {
              "filename": "budget.xlsx",
              "relative_path": "budget.xlsx",
              "size_bytes": 20480,
              "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
            }
          ],
          "link_type": "public"
        }
      },
      "UploadArtifactPlan": {
        "type": "object",
        "description": "How to send the upload's bytes. Always follow this plan; don't pick a chunk size yourself.",
        "required": [
          "file_id",
          "size_bytes",
          "chunk_size",
          "total_chunks"
        ],
        "properties": {
          "file_id": {
            "type": "string",
            "description": "The ID to use as `file_id` in upload URLs. Always the same as `session_id`."
          },
          "size_bytes": {
            "type": "integer",
            "format": "int64",
            "description": "Exactly how many bytes to upload: the file's size, or the size your ZIP archive must have."
          },
          "chunk_size": {
            "type": "integer",
            "format": "int64",
            "description": "Bytes per chunk. `0` means send everything in one request with Upload in one request."
          },
          "total_chunks": {
            "type": "integer",
            "description": "How many chunks to send, numbered from 1. `0` when `chunk_size` is `0`."
          }
        }
      },
      "UploadSessionFile": {
        "type": "object",
        "required": [
          "session_file_id",
          "filename",
          "entry_index"
        ],
        "properties": {
          "session_file_id": {
            "type": "string",
            "description": "Identifies the file in `skip_file_ids` when you finish the upload."
          },
          "filename": {
            "type": "string"
          },
          "entry_name": {
            "type": "string",
            "description": "`multi` and `folder`: the name to give this file inside your ZIP archive. It may differ from what you sent: names are cleaned up and made unique."
          },
          "entry_index": {
            "type": "integer",
            "description": "`multi` and `folder`: the file's position in the archive, from 0."
          }
        }
      },
      "UploadSession": {
        "type": "object",
        "required": [
          "session_id",
          "expires_at",
          "files",
          "artifact",
          "direct_upload",
          "upload_limit_bps"
        ],
        "properties": {
          "session_id": {
            "type": "string",
            "description": "The upload session's ID. It also becomes the delivered file's ID."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "The deadline to finish by. Uploading chunks moves it forward."
          },
          "files": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UploadSessionFile"
            },
            "description": "Your files, in the order you sent them."
          },
          "empty_dirs": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "`folder`: the names to give the empty folders inside your archive, in archive order, each ending in `/`."
          },
          "artifact": {
            "$ref": "#/components/schemas/UploadArtifactPlan"
          },
          "direct_upload": {
            "type": "boolean",
            "description": "`true` when chunks can go straight to the storage bucket through Get upload URLs for chunks."
          },
          "upload_limit_bps": {
            "type": "integer",
            "format": "int64",
            "description": "The most you can send to the server, in bits per second, or `0` for no limit. Uploads straight to the bucket are not limited."
          },
          "generated_password": {
            "type": "string",
            "description": "The link's password, when you asked Dew to generate one (`auto_generate` without a password). This is the only time it is returned."
          }
        }
      },
      "UploadSessionFilesAdded": {
        "type": "object",
        "required": [
          "files",
          "artifact"
        ],
        "properties": {
          "files": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UploadSessionFile"
            },
            "description": "The new files. They come after every earlier file in the archive."
          },
          "artifact": {
            "$ref": "#/components/schemas/UploadArtifactPlan"
          }
        }
      },
      "UploadSessionStatus": {
        "type": "object",
        "required": [
          "session_id",
          "status",
          "session_type",
          "total_files",
          "created_at",
          "expires_at",
          "artifact",
          "artifact_status"
        ],
        "properties": {
          "session_id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "finalizing",
              "completed",
              "failed",
              "expired"
            ],
            "description": "`active`: accepting bytes. `finalizing`: being finished. `completed`: the shared link exists. `failed`: finishing failed on the server; finish again. `expired`: start a new upload."
          },
          "session_type": {
            "type": "string",
            "enum": [
              "single",
              "multi",
              "folder"
            ]
          },
          "total_files": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "artifact": {
            "$ref": "#/components/schemas/UploadArtifactPlan"
          },
          "artifact_status": {
            "type": "string",
            "enum": [
              "pending",
              "completed"
            ],
            "description": "`completed` once an upload in one request arrived or the upload finished. Chunk progress is under List uploaded chunks."
          }
        }
      },
      "UploadChunkProgress": {
        "type": "object",
        "required": [
          "session_file_id",
          "completed_chunks",
          "uploaded_bytes",
          "total_bytes",
          "chunk_size",
          "total_chunks"
        ],
        "properties": {
          "session_file_id": {
            "type": "string",
            "description": "The upload's `file_id`."
          },
          "completed_chunks": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "description": "Chunk numbers the server already has, including chunks sent straight to the bucket. Skip these when resuming."
          },
          "uploaded_bytes": {
            "type": "integer",
            "format": "int64"
          },
          "total_bytes": {
            "type": "integer",
            "format": "int64"
          },
          "chunk_size": {
            "type": "integer",
            "format": "int64"
          },
          "total_chunks": {
            "type": "integer"
          }
        }
      },
      "UploadPartUrls": {
        "type": "object",
        "required": [
          "urls"
        ],
        "properties": {
          "urls": {
            "type": "object",
            "additionalProperties": {
              "type": "string",
              "format": "uri"
            },
            "description": "One URL per chunk number. `PUT` exactly that chunk's bytes to it. URLs stop working after 6 hours: if the bucket answers 403, get a new URL and try again."
          }
        }
      },
      "UploadFinishResult": {
        "type": "object",
        "required": [
          "files"
        ],
        "properties": {
          "files": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FileUploadResult"
            },
            "description": "`single`: the delivered file. Empty for `multi` and `folder`."
          },
          "zip_file": {
            "allOf": [
              {
                "$ref": "#/components/schemas/FileUploadResult"
              }
            ],
            "description": "`multi` and `folder`: the archive and its shared link, which opens a page listing the files."
          }
        }
      },
      "FileRequestPerson": {
        "type": "object",
        "description": "Someone on a file request: a person you invited, or someone who sent files through the shared link.",
        "required": [
          "id",
          "email",
          "source",
          "email_verified",
          "created_at",
          "file_count"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The person's ID on this request."
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "name": {
            "type": "string",
            "description": "The name they gave when sending files through the shared link."
          },
          "source": {
            "type": "string",
            "enum": [
              "invite",
              "link"
            ],
            "description": "`invite` for people you invited, `link` for people who came through the shared link. People who opened the shared link but never sent files are not listed."
          },
          "email_verified": {
            "type": "boolean",
            "description": "Whether the address is confirmed: always for invitees, and for shared-link senders who confirmed it with a code."
          },
          "invite_failed_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the invitation email couldn't be delivered. Left out once a later invitation goes through."
          },
          "reminded_at": {
            "type": "string",
            "format": "date-time",
            "description": "When they were last sent a reminder."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "file_count": {
            "type": "integer",
            "description": "How many files they have sent."
          }
        }
      },
      "FileRequest": {
        "type": "object",
        "description": "A file request with its people and totals.",
        "required": [
          "id",
          "creator_id",
          "domain_hostname",
          "created_at",
          "due_at",
          "link_enabled",
          "notify_mode",
          "people",
          "file_count",
          "total_size",
          "new_upload_count",
          "link_count",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "creator_id": {
            "type": "string",
            "description": "The ID of the user who owns the request."
          },
          "label": {
            "type": "string",
            "description": "The title."
          },
          "message": {
            "type": "string",
            "description": "Instructions shown to people sending files. Left out when empty."
          },
          "domain_hostname": {
            "type": "string",
            "description": "The domain the request and its upload links are on."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "due_at": {
            "type": "string",
            "format": "date-time",
            "description": "The deadline. The request closes then unless closed earlier."
          },
          "closed_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the request was closed by hand."
          },
          "deletes_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the request and every file received through it are permanently deleted. Left out when your administrator keeps received files until deleted."
          },
          "link_enabled": {
            "type": "boolean",
            "description": "Whether the shared link is on."
          },
          "notify_mode": {
            "type": "string",
            "enum": [
              "each",
              "digest",
              "off"
            ],
            "description": "Email notifications to the owner: one per upload (`each`), a daily summary (`digest`) or none (`off`)."
          },
          "people": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/FileRequestPerson"
            },
            "description": "Everyone on the request. In the list of requests, `null` when there is nobody yet."
          },
          "file_count": {
            "type": "integer",
            "description": "How many files the request has received."
          },
          "total_size": {
            "type": "integer",
            "format": "int64",
            "description": "Their total size in bytes."
          },
          "new_upload_count": {
            "type": "integer",
            "description": "Uploads not yet marked as seen."
          },
          "last_submitted_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the latest upload arrived."
          },
          "link_count": {
            "type": "integer",
            "description": "How many shared links made from received files still share them. Those files are kept after the request is deleted."
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "closed"
            ],
            "description": "`closed` once closed by hand or past the deadline."
          },
          "closed_since": {
            "type": "string",
            "format": "date-time",
            "description": "When the request closed: the manual close, else the deadline."
          },
          "link_url": {
            "type": "string",
            "format": "uri",
            "description": "The shared link people use to send files. Left out while the link is off or your administrator has turned off shared links for file requests."
          }
        }
      },
      "UpdatedFileRequest": {
        "type": "object",
        "description": "A file request's settings after a change. Fetch the request for its people, totals, status and shared link.",
        "required": [
          "id",
          "creator_id",
          "domain_hostname",
          "created_at",
          "due_at",
          "link_enabled",
          "notify_mode"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "creator_id": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "domain_hostname": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "due_at": {
            "type": "string",
            "format": "date-time"
          },
          "closed_at": {
            "type": "string",
            "format": "date-time"
          },
          "deletes_at": {
            "type": "string",
            "format": "date-time"
          },
          "link_enabled": {
            "type": "boolean"
          },
          "notify_mode": {
            "type": "string",
            "enum": [
              "each",
              "digest",
              "off"
            ]
          }
        }
      },
      "FileRequestUpload": {
        "type": "object",
        "description": "One upload a request received: a single file, or several files and folders sent together, stored as one ZIP.",
        "required": [
          "file_id",
          "name",
          "size",
          "mime_type",
          "kind",
          "file_count",
          "sender_email",
          "received_at",
          "is_new",
          "link_count"
        ],
        "properties": {
          "file_id": {
            "type": "string",
            "description": "The upload's ID, used by the received-file endpoints."
          },
          "name": {
            "type": "string"
          },
          "size": {
            "type": "integer",
            "format": "int64",
            "description": "Size in bytes."
          },
          "mime_type": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "file",
              "archive"
            ],
            "description": "`file` for a single file, `archive` for several files sent together."
          },
          "file_count": {
            "type": "integer",
            "description": "How many files the upload holds."
          },
          "sender_email": {
            "type": "string",
            "format": "email"
          },
          "sender_name": {
            "type": "string"
          },
          "sender_message": {
            "type": "string",
            "description": "The note the sender added, up to 500 characters."
          },
          "recipient_id": {
            "type": "string",
            "description": "The sender's person ID. Left out when that person was removed from the request."
          },
          "received_at": {
            "type": "string",
            "format": "date-time"
          },
          "is_new": {
            "type": "boolean",
            "description": "Not yet marked as seen."
          },
          "link_count": {
            "type": "integer",
            "description": "How many shared links made from this upload still share it."
          }
        }
      },
      "FileRequestActivity": {
        "type": "object",
        "description": "One event on a file request.",
        "required": [
          "event_type",
          "timestamp"
        ],
        "properties": {
          "event_type": {
            "type": "string",
            "description": "The audit event, such as `file_request.created` or `file.deleted`."
          },
          "actor_email": {
            "type": "string"
          },
          "actor_name": {
            "type": "string"
          },
          "target_name": {
            "type": "string"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true,
            "description": "Details of the event."
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "FileRequestDetail": {
        "type": "object",
        "required": [
          "file_request",
          "uploads",
          "activity"
        ],
        "properties": {
          "file_request": {
            "$ref": "#/components/schemas/FileRequest"
          },
          "uploads": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FileRequestUpload"
            },
            "description": "Every upload, newest first."
          },
          "activity": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FileRequestActivity"
            },
            "description": "The latest events on the request, up to 50, newest first."
          }
        }
      },
      "FileRequestEmailResult": {
        "type": "object",
        "required": [
          "emails"
        ],
        "properties": {
          "emails": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "email"
            },
            "description": "Addresses being emailed. The emails go out after the response; a person the email couldn't reach gets `invite_failed_at` on the request."
          }
        }
      },
      "ReceivedFolderItem": {
        "type": "object",
        "description": "A file or folder inside an upload of several files.",
        "required": [
          "name",
          "path",
          "is_dir",
          "file_count",
          "size"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "path": {
            "type": "string",
            "description": "The path to pass to the entry, download and link endpoints. Folders end in `/`."
          },
          "is_dir": {
            "type": "boolean"
          },
          "file_count": {
            "type": "integer",
            "description": "For a folder, how many files are under it; 1 for a file."
          },
          "size": {
            "type": "integer",
            "format": "int64",
            "description": "Size in bytes; for a folder, of everything under it."
          }
        }
      },
      "ReceivedFile": {
        "type": "object",
        "description": "One file a request received, wherever it is.",
        "required": [
          "file_id",
          "path",
          "name",
          "size",
          "sender_email",
          "received_at"
        ],
        "properties": {
          "file_id": {
            "type": "string",
            "description": "The upload it belongs to."
          },
          "path": {
            "type": "string",
            "description": "Its path inside the upload. Empty for a single-file upload."
          },
          "name": {
            "type": "string"
          },
          "size": {
            "type": "integer",
            "format": "int64"
          },
          "sender_email": {
            "type": "string",
            "format": "email"
          },
          "sender_name": {
            "type": "string"
          },
          "received_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ReceivedItemSelection": {
        "type": "object",
        "description": "Part of what a request received: a whole upload, or a file or folder inside one.",
        "required": [
          "file_id"
        ],
        "properties": {
          "file_id": {
            "type": "string",
            "description": "The upload's ID."
          },
          "path": {
            "type": "string",
            "description": "Leave out or empty for the whole upload. Otherwise a file's path inside it, or a folder's path ending in `/`, as the contents endpoint lists them."
          }
        }
      },
      "ReceivedLinkSettings": {
        "type": "object",
        "description": "Who can open the new shared link.",
        "properties": {
          "link_type": {
            "type": "string",
            "enum": [
              "public",
              "protected",
              "private",
              "onetime"
            ],
            "default": "public",
            "description": "`public`: anyone with the link. `protected`: needs a password, a text message code or an email code. `private`: only from the network addresses on an allowlist. `onetime`: works for one download."
          },
          "protection_method": {
            "type": "string",
            "enum": [
              "password",
              "sms",
              "email"
            ],
            "description": "Required for `protected` links. `sms` needs text messages set up for the domain, `email` needs email set up."
          },
          "password": {
            "type": "string",
            "description": "For `password` protection."
          },
          "auto_generate": {
            "type": "boolean",
            "description": "For `password` protection without a `password`: the server picks one."
          },
          "phone_number": {
            "type": "string",
            "description": "Required for `sms` protection."
          },
          "country_code": {
            "type": "string",
            "description": "For `sms` protection."
          },
          "allowlist_id": {
            "type": "string",
            "description": "Required for `private` links: an allowlist available on the request's domain."
          },
          "email_recipients": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "email"
              ],
              "properties": {
                "email": {
                  "type": "string",
                  "format": "email"
                }
              }
            },
            "description": "For `email` protection: the people who may open the link. Each is emailed an invitation."
          },
          "email_message": {
            "type": "string",
            "description": "For `email` protection: a message included in the invitation."
          }
        }
      },
      "ReceivedFileLink": {
        "type": "object",
        "required": [
          "file",
          "url",
          "formatted_text"
        ],
        "properties": {
          "file": {
            "type": "object",
            "description": "The new file behind the link. It is yours and appears with your other files.",
            "required": [
              "id",
              "name",
              "size",
              "mime_type",
              "link_type",
              "domain_hostname"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "size": {
                "type": "integer",
                "format": "int64"
              },
              "mime_type": {
                "type": "string"
              },
              "link_type": {
                "type": "string",
                "enum": [
                  "public",
                  "protected",
                  "private",
                  "onetime"
                ]
              },
              "protection_method": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "password",
                  "sms",
                  "email",
                  null
                ]
              },
              "domain_hostname": {
                "type": "string"
              },
              "expires_at": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time",
                "description": "When the link expires, from your administrator's link expiry. `null` when it never expires."
              }
            }
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The shared link."
          },
          "formatted_text": {
            "type": "string",
            "description": "The link as your administrator's link template formats it, ready to paste."
          },
          "generated_password": {
            "type": "string",
            "description": "The link's password, when you asked Dew to generate one (`auto_generate` without a password). This is the only time it is returned."
          }
        }
      },
      "AdminUser": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The user's ID."
          },
          "displayname": {
            "type": "string",
            "description": "The user's name."
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "user_status": {
            "type": "string",
            "enum": [
              "active",
              "inactive"
            ],
            "description": "`inactive` users can't sign in and don't take a seat."
          },
          "is_admin": {
            "type": "boolean"
          },
          "domain_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of the domains the user has access to, through their own place on a domain's access list or through a group."
          },
          "auth_provider": {
            "type": "string",
            "description": "How the user signs in: `local` for a password, otherwise the single sign-on type, such as `saml`."
          },
          "is_break_glass": {
            "type": "boolean",
            "description": "The emergency admin who can always sign in with a password."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "is_scim_connection": {
            "type": "boolean",
            "description": "The user's single sign-on connection uses SCIM, so their status and SCIM groups are managed in the identity provider."
          },
          "is_sso_orphan": {
            "type": "boolean",
            "description": "The user signs in with single sign-on, but their email domain is no longer on the connection, so they can't sign in until the domain is added back or the account is converted to a password account."
          },
          "avatar_url": {
            "type": "string",
            "description": "The user's profile picture, or an empty string when they have none."
          }
        },
        "required": [
          "id",
          "displayname",
          "email",
          "user_status",
          "is_admin",
          "domain_ids",
          "auth_provider",
          "is_break_glass",
          "created_at",
          "is_scim_connection",
          "is_sso_orphan",
          "avatar_url"
        ]
      },
      "CreateUserRequest": {
        "type": "object",
        "required": [
          "displayname",
          "email",
          "password"
        ],
        "properties": {
          "displayname": {
            "type": "string",
            "minLength": 1,
            "description": "The user's name."
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Stored in lowercase. Must not belong to another user."
          },
          "password": {
            "type": "string",
            "minLength": 1,
            "description": "Must meet the server's password policy."
          },
          "is_admin": {
            "type": "boolean",
            "default": false,
            "description": "Must be `false` under an API token."
          },
          "domain_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Domains whose access list the user is put on, by ID from `GET /api/admin/domains`. Required under an API token, and only the service account's domains."
          },
          "group_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Local groups the user joins, by ID from `GET /api/admin/groups`. Under an API token, needs `groups:write`."
          }
        }
      },
      "CreatedUser": {
        "type": "object",
        "required": [
          "id"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The new user's ID."
          }
        }
      },
      "UserDeleteImpact": {
        "type": "object",
        "required": [
          "shared_links",
          "file_requests",
          "received_files"
        ],
        "properties": {
          "shared_links": {
            "type": "integer",
            "minimum": 0,
            "description": "Files the user uploaded, each with its shared link."
          },
          "file_requests": {
            "type": "integer",
            "minimum": 0,
            "description": "File requests the user created."
          },
          "received_files": {
            "type": "integer",
            "minimum": 0,
            "description": "Files the user received through their file requests."
          }
        }
      },
      "TransferOwnershipRequest": {
        "type": "object",
        "required": [
          "to_user_id"
        ],
        "properties": {
          "to_user_id": {
            "type": "string",
            "description": "ID of the user who receives the files and file requests. Must be another active user."
          }
        }
      },
      "SetUserStatusRequest": {
        "type": "object",
        "required": [
          "user_status"
        ],
        "properties": {
          "user_status": {
            "type": "string",
            "enum": [
              "active",
              "inactive"
            ],
            "description": "Case-insensitive."
          }
        }
      },
      "UserAccess": {
        "type": "object",
        "required": [
          "groups",
          "domains"
        ],
        "properties": {
          "groups": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserGroup"
            },
            "description": "The groups the user is in or excluded from: Everyone first, then by name."
          },
          "domains": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserDomainAccess"
            },
            "description": "Every domain the user has access to, by hostname."
          }
        }
      },
      "UserGroup": {
        "type": "object",
        "required": [
          "id",
          "kind",
          "name",
          "source"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The group's ID."
          },
          "kind": {
            "type": "string",
            "enum": [
              "local",
              "scim",
              "everyone"
            ],
            "description": "`local` made in Dew, `scim` synced from the identity provider, `everyone` the built-in group of every user."
          },
          "name": {
            "type": "string"
          },
          "source": {
            "type": "string",
            "enum": [
              "added",
              "rule",
              "everyone",
              "excluded"
            ],
            "description": "`added` by an admin or the identity provider, `rule` by the group's email rule, `everyone` for Everyone, `excluded` when the rule matches but the user was excluded."
          }
        }
      },
      "UserDomainAccess": {
        "type": "object",
        "required": [
          "domain_id",
          "hostname",
          "is_active",
          "routes"
        ],
        "properties": {
          "domain_id": {
            "type": "string"
          },
          "hostname": {
            "type": "string"
          },
          "is_active": {
            "type": "boolean",
            "description": "The domain is turned on."
          },
          "routes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AccessRoute"
            },
            "description": "How the user has access: their own place on the access list first, then each group."
          }
        }
      },
      "AccessRoute": {
        "type": "object",
        "description": "One way a user has access to a domain. Without `group_id`, the user is on the domain's access list themselves.",
        "properties": {
          "group_id": {
            "type": "string",
            "description": "The group that gives access. Left out when the user is on the access list themselves."
          },
          "group_name": {
            "type": "string",
            "description": "Left out when the user is on the access list themselves."
          }
        }
      },
      "Group": {
        "type": "object",
        "required": [
          "id",
          "kind",
          "name",
          "email_domains",
          "member_count",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The group's ID. Everyone's is `everyone`."
          },
          "kind": {
            "type": "string",
            "enum": [
              "local",
              "scim",
              "everyone"
            ],
            "description": "`local` made in Dew, `scim` synced from the identity provider, `everyone` the built-in group of every user except service accounts. Only Local groups can be changed here."
          },
          "name": {
            "type": "string"
          },
          "email_domains": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The email rule: users with an email at one of these domains are members. Empty when there is no rule."
          },
          "member_count": {
            "type": "integer",
            "minimum": 0
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "GroupDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Group"
          },
          {
            "type": "object",
            "required": [
              "members",
              "access"
            ],
            "properties": {
              "members": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/GroupMember"
                },
                "description": "The members by email, then the people the rule matches who are excluded. Empty for Everyone, which is every user."
              },
              "access": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/GroupAccess"
                },
                "description": "The domains whose access list the group is on, by hostname."
              }
            }
          }
        ]
      },
      "GroupMember": {
        "type": "object",
        "required": [
          "user_id",
          "email",
          "displayname",
          "source",
          "avatar_url"
        ],
        "properties": {
          "user_id": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "displayname": {
            "type": "string"
          },
          "source": {
            "type": "string",
            "enum": [
              "added",
              "rule",
              "excluded"
            ],
            "description": "`added` by an admin or the identity provider, `rule` by the group's email rule, `excluded` when the rule matches but the user was excluded and is not a member."
          },
          "avatar_url": {
            "type": "string",
            "description": "The user's profile picture, or an empty string when they have none."
          }
        }
      },
      "GroupAccess": {
        "type": "object",
        "required": [
          "domain_id",
          "hostname",
          "sole_access_count"
        ],
        "properties": {
          "domain_id": {
            "type": "string"
          },
          "hostname": {
            "type": "string"
          },
          "sole_access_count": {
            "type": "integer",
            "minimum": 0,
            "description": "How many users would lose access to the domain if the group were taken off its access list. Admins never do."
          }
        }
      },
      "GroupRequest": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "Must not be the name of another Local group or Everyone, ignoring case."
          },
          "email_domains": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The email rule, such as `example.com`: users with an email at these domains become members. Leave out or empty for no rule. API tokens can't set or change it: a request that would is refused with 403."
          }
        }
      },
      "GroupMembersRequest": {
        "type": "object",
        "required": [
          "user_ids"
        ],
        "properties": {
          "user_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "description": "The users to add, by ID."
          }
        }
      },
      "CreateInviteRequest": {
        "type": "object",
        "required": [
          "email"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "description": "Who to invite. Must not belong to an existing user."
          },
          "domain_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Domains the person gets access to when they accept. The invitation link uses the first active one, or the primary domain."
          },
          "source_domain_id": {
            "type": "string",
            "description": "The domain whose email settings and branding the invitation uses. Leave out to use the global settings."
          },
          "is_admin": {
            "type": "boolean",
            "default": false,
            "description": "Must be `false` under an API token."
          },
          "group_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Local groups the person joins when they accept, by ID from `GET /api/admin/groups`. Under an API token, needs `groups:write`."
          }
        }
      },
      "Invite": {
        "type": "object",
        "required": [
          "id",
          "email",
          "domain_ids",
          "group_ids",
          "expires_at",
          "created_at",
          "expired"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The invitation's ID."
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "domain_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Domains the person gets access to when they accept."
          },
          "group_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Local groups the person joins when they accept."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expired": {
            "type": "boolean",
            "description": "The invitation link no longer works. The invitation can still be resent."
          }
        }
      },
      "AdminClientDevice": {
        "type": "object",
        "required": [
          "id",
          "user_id",
          "user_email",
          "device_name",
          "platform",
          "os_version",
          "app_version",
          "first_seen_at",
          "last_seen_at",
          "last_ip"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The device's ID, used to sign it out."
          },
          "user_id": {
            "type": "string"
          },
          "user_email": {
            "type": "string",
            "format": "email"
          },
          "device_name": {
            "type": "string",
            "description": "The computer's name, as the desktop app reports it."
          },
          "platform": {
            "type": "string",
            "description": "The operating system, as the desktop app reports it."
          },
          "os_version": {
            "type": "string"
          },
          "app_version": {
            "type": "string"
          },
          "first_seen_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the desktop app first signed in on this computer."
          },
          "last_seen_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the desktop app last signed in on this computer."
          },
          "last_used_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the desktop app last made a request. Left out when unknown."
          },
          "last_ip": {
            "type": "string",
            "description": "The IP address of the last sign-in."
          }
        }
      },
      "SmtpConfig": {
        "type": "object",
        "description": "A named email sending setup: an SMTP server or a Microsoft 365 (Microsoft Graph) app registration. Passwords and client secrets are never returned, only whether one is saved.",
        "required": [
          "id",
          "name",
          "is_default",
          "is_active",
          "provider",
          "host",
          "port",
          "encryption",
          "password_set",
          "from_email",
          "created_at",
          "updated_at",
          "ms_client_secret_set"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Email setup ID."
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "description": "Left out when empty."
          },
          "is_default": {
            "type": "boolean",
            "description": "Whether this is the server-wide default for sending email."
          },
          "is_active": {
            "type": "boolean"
          },
          "provider": {
            "type": "string",
            "enum": [
              "smtp",
              "microsoft_graph"
            ],
            "description": "How email is sent."
          },
          "host": {
            "type": "string",
            "description": "SMTP server host. Empty for Microsoft Graph."
          },
          "port": {
            "type": "integer",
            "description": "SMTP server port."
          },
          "encryption": {
            "type": "string",
            "enum": [
              "none",
              "starttls",
              "tls"
            ],
            "description": "SMTP connection security."
          },
          "username": {
            "type": "string",
            "description": "SMTP user name. Left out when not set."
          },
          "password_set": {
            "type": "boolean",
            "description": "Whether an SMTP password is saved. The password itself is never returned."
          },
          "from_email": {
            "type": "string",
            "format": "email",
            "description": "Sender address. For Microsoft Graph, the mailbox the app sends as."
          },
          "from_name": {
            "type": "string",
            "description": "Sender name. Left out when not set."
          },
          "reply_to": {
            "type": "string",
            "description": "Reply-to address. Left out when not set."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "ms_tenant_id": {
            "type": "string",
            "description": "Microsoft Graph only: the Entra tenant ID."
          },
          "ms_client_id": {
            "type": "string",
            "description": "Microsoft Graph only: the app registration's client ID."
          },
          "ms_client_secret_set": {
            "type": "boolean",
            "description": "Microsoft Graph only: whether a client secret is saved. The secret itself is never returned."
          },
          "ms_secret_expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "Microsoft Graph only: when the client secret expires, as entered by the admin."
          }
        }
      },
      "SmsConfig": {
        "type": "object",
        "description": "A named text message (SMS) provider setup. API keys are never returned, only whether one is saved.",
        "required": [
          "id",
          "name",
          "is_default",
          "is_active",
          "provider_type",
          "api_key_set",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "SMS setup ID."
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "description": "Left out when empty."
          },
          "is_default": {
            "type": "boolean",
            "description": "Whether this is the server-wide default for sending text messages."
          },
          "is_active": {
            "type": "boolean"
          },
          "provider_type": {
            "type": "string",
            "enum": [
              "suresms",
              "twilio",
              "textmagic"
            ]
          },
          "api_key_set": {
            "type": "boolean",
            "description": "Whether an API key or auth token is saved. The key itself is never returned."
          },
          "account_sid": {
            "type": "string",
            "description": "Twilio only: the account SID. Left out when empty."
          },
          "username": {
            "type": "string",
            "description": "TextMagic only: the account user name. Left out when empty."
          },
          "needs_sender": {
            "type": "boolean",
            "description": "List only, Twilio only: true when this setup is in use but no sender is saved, so text messages can't be sent. Left out when false."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "GlobalSettings": {
        "type": "object",
        "description": "Server-wide settings. Domains use these unless their own settings override them.",
        "properties": {
          "storage_provider": {
            "type": "string",
            "description": "ID of the default storage provider."
          },
          "max_upload_size_gb": {
            "type": "integer",
            "description": "Largest upload allowed, in GB."
          },
          "link_expiry_days": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Days until a new shared link expires. null: 30 days."
          },
          "max_link_lifetime_days": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Longest lifetime a shared link may be given, in days. null: the same as link_expiry_days."
          },
          "link_format_template": {
            "type": [
              "string",
              "null"
            ],
            "description": "Template for the text copied with a new link; it must contain `<file_link>`. null: the built-in format."
          },
          "blocked_file_extensions": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "File extensions that can't be uploaded."
          },
          "upload_limit_per_ip_mbps": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Upload bandwidth limit per IP address, in Mbit/s. null: no limit."
          },
          "upload_limit_total_mbps": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Total upload bandwidth limit, in Mbit/s. null: no limit."
          },
          "upload_limit_exempt_local": {
            "type": "boolean",
            "description": "Whether uploads from local networks skip the bandwidth limits."
          },
          "enable_admin_ip_allowlist": {
            "type": "boolean",
            "description": "Whether admin access is limited to the addresses in admin_dashboard_allowed_ips."
          },
          "admin_dashboard_allowed_ips": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IP addresses and CIDR ranges admin access is allowed from."
          },
          "private_links_enabled": {
            "type": "boolean",
            "description": "Whether private links (restricted to allowed networks) are turned on."
          },
          "smtp_config_id": {
            "type": "string",
            "description": "ID of the default email setup. Left out when none is chosen."
          },
          "sms_config_id": {
            "type": "string",
            "description": "ID of the default SMS setup. Left out when none is chosen."
          },
          "sms_sender_name": {
            "type": "string",
            "description": "Sender name for text messages. Left out when not set."
          },
          "display_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Name shown to people instead of the product name. null: not set."
          },
          "has_logo": {
            "type": "boolean"
          },
          "logo_not_email_safe": {
            "type": "boolean",
            "description": "The logo is SVG or WebP, which some email apps don't show."
          },
          "has_favicon": {
            "type": "boolean"
          },
          "has_background": {
            "type": "boolean"
          },
          "accent_color": {
            "type": [
              "string",
              "null"
            ],
            "description": "Accent color, such as `#2563eb`. null: not set."
          },
          "email_invite_subject": {
            "type": [
              "string",
              "null"
            ]
          },
          "email_invite_title": {
            "type": [
              "string",
              "null"
            ]
          },
          "email_invite_body": {
            "type": [
              "string",
              "null"
            ]
          },
          "email_alert_subject": {
            "type": [
              "string",
              "null"
            ]
          },
          "email_alert_title": {
            "type": [
              "string",
              "null"
            ]
          },
          "email_alert_body": {
            "type": [
              "string",
              "null"
            ]
          },
          "email_footer": {
            "type": [
              "string",
              "null"
            ]
          },
          "audit_log_retention_days": {
            "type": "integer",
            "description": "Days audit log entries are kept."
          },
          "received_file_retention_days": {
            "type": "integer",
            "description": "Days files sent to file requests are kept."
          },
          "allow_link_file_requests": {
            "type": "boolean",
            "description": "Whether file requests can be shared as an upload link anyone can use."
          },
          "require_link_upload_verification": {
            "type": "boolean",
            "description": "Whether people sending files through an upload link must confirm their email address first."
          },
          "avatars_enabled": {
            "type": "boolean",
            "description": "Whether users can upload profile pictures."
          },
          "personal_tokens_enabled": {
            "type": "boolean",
            "description": "Whether users can create personal API tokens."
          },
          "email_configured": {
            "type": "boolean",
            "description": "Whether email can be sent anywhere on the server: server-wide or from at least one domain."
          },
          "disable_zip_browser": {
            "type": "boolean",
            "description": "Whether browsing inside ZIP files on the download page is turned off."
          },
          "sanitize_windows_filenames": {
            "type": "boolean",
            "description": "Whether file names are made safe for Windows on download."
          },
          "enable_sspr": {
            "type": "boolean",
            "description": "Whether users can reset a forgotten password themselves."
          },
          "require_2fa": {
            "type": "string",
            "enum": [
              "none",
              "admins",
              "all"
            ],
            "description": "Who must use two-step verification."
          },
          "password_policy_mode": {
            "type": "string",
            "enum": [
              "simple",
              "advanced"
            ]
          },
          "password_min_length": {
            "type": "integer"
          },
          "password_require_mixed_case": {
            "type": "boolean"
          },
          "password_require_number": {
            "type": "boolean"
          },
          "password_require_symbol": {
            "type": "boolean"
          },
          "password_regex": {
            "type": "string",
            "description": "The pattern passwords must match."
          },
          "password_guidance": {
            "type": "string",
            "description": "The password rules shown to users."
          },
          "link_not_found_behavior": {
            "type": "string",
            "enum": [
              "informative",
              "generic",
              "redirect"
            ],
            "description": "What people see when a link doesn't exist."
          },
          "link_not_found_redirect_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Where people are sent when link_not_found_behavior is `redirect`."
          },
          "session_lifetime_hours": {
            "type": "integer",
            "description": "Hours a sign-in lasts."
          },
          "idle_timeout_enabled": {
            "type": "boolean"
          },
          "idle_timeout_hours": {
            "type": "integer"
          },
          "alert_cert_expiry_enabled": {
            "type": "boolean"
          },
          "alert_storage_enabled": {
            "type": "boolean"
          },
          "alert_storage_threshold_pct": {
            "type": "integer",
            "description": "Storage use, in percent, that raises an alert."
          },
          "alert_storage_health_enabled": {
            "type": "boolean"
          },
          "alert_license_enabled": {
            "type": "boolean"
          },
          "alert_email_provider_enabled": {
            "type": "boolean"
          },
          "alert_api_token_enabled": {
            "type": "boolean"
          },
          "alert_version_enabled": {
            "type": "boolean",
            "description": "Whether admins are emailed once for each newer server version the update check finds."
          },
          "update_check_enabled": {
            "type": "boolean",
            "description": "Whether the server checks getdew.io once a day for a newer version."
          }
        },
        "required": [
          "storage_provider",
          "max_upload_size_gb",
          "link_expiry_days",
          "max_link_lifetime_days",
          "link_format_template",
          "blocked_file_extensions",
          "upload_limit_per_ip_mbps",
          "upload_limit_total_mbps",
          "upload_limit_exempt_local",
          "enable_admin_ip_allowlist",
          "admin_dashboard_allowed_ips",
          "private_links_enabled",
          "display_name",
          "has_logo",
          "logo_not_email_safe",
          "has_favicon",
          "has_background",
          "accent_color",
          "email_invite_subject",
          "email_invite_title",
          "email_invite_body",
          "email_alert_subject",
          "email_alert_title",
          "email_alert_body",
          "email_footer",
          "audit_log_retention_days",
          "received_file_retention_days",
          "allow_link_file_requests",
          "require_link_upload_verification",
          "avatars_enabled",
          "personal_tokens_enabled",
          "email_configured",
          "disable_zip_browser",
          "sanitize_windows_filenames",
          "enable_sspr",
          "require_2fa",
          "password_policy_mode",
          "password_min_length",
          "password_require_mixed_case",
          "password_require_number",
          "password_require_symbol",
          "password_regex",
          "password_guidance",
          "link_not_found_behavior",
          "link_not_found_redirect_url",
          "session_lifetime_hours",
          "idle_timeout_enabled",
          "idle_timeout_hours",
          "alert_cert_expiry_enabled",
          "alert_storage_enabled",
          "alert_storage_threshold_pct",
          "alert_storage_health_enabled",
          "alert_license_enabled",
          "alert_email_provider_enabled",
          "alert_api_token_enabled",
          "alert_version_enabled",
          "update_check_enabled"
        ]
      },
      "CertificateFolder": {
        "type": "object",
        "description": "A certificate folder on the server. Only the file locations are returned, never the certificate or key contents.",
        "required": [
          "cert_name",
          "cert_path",
          "key_path"
        ],
        "properties": {
          "cert_name": {
            "type": "string",
            "description": "Folder name, used as a domain's certificate name."
          },
          "cert_path": {
            "type": "string",
            "description": "Location of the certificate file on the server."
          },
          "key_path": {
            "type": "string",
            "description": "Location of the private key file on the server. The key itself is never returned."
          }
        }
      },
      "DomainCertStatus": {
        "type": "object",
        "description": "The certificate a domain serves and its state.",
        "required": [
          "hostname",
          "cert_name",
          "cert_path",
          "key_path",
          "loaded",
          "auto_renew"
        ],
        "properties": {
          "hostname": {
            "type": "string"
          },
          "cert_name": {
            "type": "string",
            "description": "Certificate folder name."
          },
          "cert_path": {
            "type": "string",
            "description": "Location of the certificate file on the server. Empty for Let's Encrypt."
          },
          "key_path": {
            "type": "string",
            "description": "Location of the private key file on the server. Empty for Let's Encrypt. The key itself is never returned."
          },
          "loaded": {
            "type": "boolean",
            "description": "Whether the certificate is loaded and served."
          },
          "self_signed": {
            "type": "boolean",
            "description": "Left out when false."
          },
          "status": {
            "type": "string",
            "description": "`valid` when a current Let's Encrypt certificate was found. Left out otherwise."
          },
          "issuer": {
            "type": "string",
            "description": "Let's Encrypt only: the issuer's name. Left out otherwise."
          },
          "error": {
            "type": "string",
            "description": "Why the certificate isn't loaded, as reported by the server. Left out when there is no problem."
          },
          "dns_names": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Host names the certificate covers."
          },
          "not_after_unix": {
            "type": "integer",
            "format": "int64",
            "description": "Expiry as a Unix timestamp."
          },
          "not_before_unix": {
            "type": "integer",
            "format": "int64",
            "description": "Start of validity as a Unix timestamp."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "Expiry."
          },
          "acme_email": {
            "type": "string",
            "description": "Let's Encrypt only: the account email."
          },
          "acme_cert_expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "acme_last_success_at": {
            "type": "string",
            "format": "date-time"
          },
          "acme_last_attempt_at": {
            "type": "string",
            "format": "date-time"
          },
          "acme_last_error": {
            "type": "string",
            "description": "Let's Encrypt only: the last issuance error."
          },
          "acme_renewal_window": {
            "type": "string",
            "format": "date-time",
            "description": "Let's Encrypt only: when renewal starts, 30 days before expiry."
          },
          "auto_renew": {
            "type": "boolean",
            "description": "True for Let's Encrypt certificates."
          }
        }
      },
      "Domain": {
        "type": "object",
        "required": [
          "id",
          "hostname",
          "is_primary",
          "is_active",
          "is_verified",
          "cert_name",
          "created_at",
          "updated_at",
          "cert_status"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Domain ID."
          },
          "hostname": {
            "type": "string"
          },
          "is_primary": {
            "type": "boolean"
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the domain is served."
          },
          "is_verified": {
            "type": "boolean",
            "description": "Whether the domain's DNS has been verified. A domain can be active but not verified."
          },
          "verified_at": {
            "type": "string",
            "format": "date-time"
          },
          "last_verified_at": {
            "type": "string",
            "format": "date-time"
          },
          "cert_name": {
            "type": "string",
            "description": "Certificate folder name."
          },
          "cert_mode": {
            "type": "string",
            "enum": [
              "manual",
              "letsencrypt"
            ],
            "description": "Where the certificate comes from."
          },
          "acme_email": {
            "type": "string"
          },
          "acme_last_error": {
            "type": "string"
          },
          "acme_last_attempt_at": {
            "type": "string",
            "format": "date-time"
          },
          "acme_last_success_at": {
            "type": "string",
            "format": "date-time"
          },
          "acme_cert_expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "hsts_enabled": {
            "type": "boolean",
            "description": "true: browsers are told to use HTTPS only, for a year. false: browsers are told to forget an earlier HTTPS-only setting. Left out when never turned on."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "cert_status": {
            "$ref": "#/components/schemas/DomainCertStatus"
          },
          "storage_provider": {
            "type": "string",
            "description": "ID of the storage provider this domain uses instead of the default. Left out when it uses the default."
          },
          "smtp_config_id": {
            "type": "string",
            "description": "ID of the email setup this domain uses instead of the default. Left out when it uses the default."
          },
          "sms_config_id": {
            "type": "string",
            "description": "ID of the SMS setup this domain uses instead of the default. Left out when it uses the default."
          }
        }
      },
      "DomainSettings": {
        "type": "object",
        "description": "A domain's own settings. A null or left-out field means the domain uses the server-wide setting.",
        "required": [
          "domain_id",
          "blocked_file_extensions",
          "has_logo",
          "logo_not_email_safe",
          "has_favicon",
          "has_background"
        ],
        "properties": {
          "domain_id": {
            "type": "string"
          },
          "storage_provider": {
            "type": [
              "string",
              "null"
            ],
            "description": "ID of the storage provider for this domain."
          },
          "max_upload_size_gb": {
            "type": [
              "integer",
              "null"
            ]
          },
          "link_expiry_days": {
            "type": [
              "integer",
              "null"
            ]
          },
          "max_link_lifetime_days": {
            "type": [
              "integer",
              "null"
            ]
          },
          "link_format_template": {
            "type": [
              "string",
              "null"
            ]
          },
          "blocked_file_extensions": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Extensions blocked on this domain. Empty when it uses the server-wide list."
          },
          "display_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "has_logo": {
            "type": "boolean"
          },
          "logo_not_email_safe": {
            "type": "boolean",
            "description": "The logo is SVG or WebP, which some email apps don't show."
          },
          "has_favicon": {
            "type": "boolean"
          },
          "has_background": {
            "type": "boolean"
          },
          "accent_color": {
            "type": [
              "string",
              "null"
            ]
          },
          "email_invite_subject": {
            "type": [
              "string",
              "null"
            ]
          },
          "email_invite_title": {
            "type": [
              "string",
              "null"
            ]
          },
          "email_invite_body": {
            "type": [
              "string",
              "null"
            ]
          },
          "email_alert_subject": {
            "type": [
              "string",
              "null"
            ]
          },
          "email_alert_title": {
            "type": [
              "string",
              "null"
            ]
          },
          "email_alert_body": {
            "type": [
              "string",
              "null"
            ]
          },
          "email_footer": {
            "type": [
              "string",
              "null"
            ]
          },
          "smtp_config_id": {
            "type": "string",
            "description": "ID of this domain's email setup. Left out when it uses the default."
          },
          "sms_config_id": {
            "type": "string",
            "description": "ID of this domain's SMS setup. Left out when it uses the default."
          },
          "sms_sender_name": {
            "type": "string",
            "description": "Left out when not set."
          },
          "private_links_mode": {
            "type": "string",
            "description": "This domain's private links setting. Left out when it uses the server-wide setting."
          },
          "disable_zip_browser": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "sanitize_windows_filenames": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "link_not_found_behavior": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "informative",
              "generic",
              "redirect",
              null
            ]
          },
          "link_not_found_redirect_url": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "PublicIp": {
        "type": "object",
        "required": [
          "ipv4"
        ],
        "properties": {
          "ipv4": {
            "type": "string",
            "description": "The server's public IPv4 address, or empty when it couldn't be found."
          }
        }
      },
      "PrivateAllowlist": {
        "type": "object",
        "description": "Networks allowed to open private links, server-wide or for one domain.",
        "required": [
          "id",
          "name",
          "cidr_ranges",
          "is_active",
          "is_global",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "description": "Left out when empty."
          },
          "domain_id": {
            "type": "string",
            "description": "The domain this list belongs to. Left out for a server-wide list."
          },
          "domain_name": {
            "type": "string",
            "description": "The domain's host name. Left out for a server-wide list."
          },
          "cidr_ranges": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Allowed networks in CIDR notation."
          },
          "is_active": {
            "type": "boolean"
          },
          "is_global": {
            "type": "boolean",
            "description": "True for a server-wide list."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "StorageProvider": {
        "type": "object",
        "description": "Where files are stored: a folder on the server, or an S3-compatible bucket. Access keys and secret keys are never returned.",
        "required": [
          "id",
          "name",
          "provider_type",
          "base_path",
          "is_active",
          "direct_upload_enabled",
          "total_bytes",
          "used_by_dew",
          "free_bytes",
          "file_count",
          "created_at",
          "is_global_default",
          "domain_override_count",
          "active_session_count",
          "is_registered"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Storage provider ID. The built-in local storage is `storage_default`."
          },
          "name": {
            "type": "string"
          },
          "provider_type": {
            "type": "string",
            "enum": [
              "local",
              "amazon-s3",
              "wasabi",
              "backblaze-b2",
              "cloudflare-r2",
              "storj",
              "custom-s3"
            ]
          },
          "base_path": {
            "type": [
              "string",
              "null"
            ],
            "description": "Local storage only: the folder files are stored in. null for buckets."
          },
          "endpoint": {
            "type": "string",
            "description": "Buckets only: the S3 endpoint URL."
          },
          "region": {
            "type": "string",
            "description": "Buckets only."
          },
          "bucket": {
            "type": "string",
            "description": "Buckets only."
          },
          "prefix": {
            "type": "string",
            "description": "Buckets only: the key prefix files are stored under."
          },
          "path_style": {
            "type": "boolean",
            "description": "Buckets only: whether path-style addressing is used. Left out when false."
          },
          "is_active": {
            "type": "boolean"
          },
          "direct_upload_enabled": {
            "type": "boolean",
            "description": "Whether browsers upload and download straight to and from the bucket."
          },
          "transfers_through_server": {
            "type": "boolean",
            "description": "Buckets only: true when the bucket is on a private network, so transfers always go through the server. Left out when false."
          },
          "total_bytes": {
            "type": "integer",
            "format": "int64",
            "description": "Disk size for local storage, -1 for buckets (no fixed size), 0 when unknown."
          },
          "used_by_dew": {
            "type": "integer",
            "format": "int64",
            "description": "Bytes taken by files on this storage."
          },
          "free_bytes": {
            "type": "integer",
            "format": "int64",
            "description": "Free disk space for local storage, -1 for buckets, 0 when unknown."
          },
          "file_count": {
            "type": "integer",
            "format": "int64"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "is_global_default": {
            "type": "boolean",
            "description": "Whether this is the server-wide default storage."
          },
          "domain_override_count": {
            "type": "integer",
            "format": "int64",
            "description": "Domains set to use this storage."
          },
          "active_session_count": {
            "type": "integer",
            "format": "int64",
            "description": "Uploads in progress on this storage."
          },
          "health_status": {
            "type": "string",
            "enum": [
              "ok",
              "mount_missing",
              "unwritable",
              "missing",
              "unverifiable"
            ],
            "description": "Local storage only: whether the folder can be written to. Left out for buckets."
          },
          "health_reason": {
            "type": "string",
            "description": "Local storage only: why health_status isn't `ok`."
          },
          "is_registered": {
            "type": "boolean",
            "description": "Whether the server is using this storage right now. False when it failed its health check at startup."
          }
        }
      },
      "StorageMountTarget": {
        "type": "object",
        "required": [
          "path",
          "fs_type",
          "is_bind",
          "writable",
          "is_system"
        ],
        "properties": {
          "path": {
            "type": "string",
            "description": "Folder path inside the server container."
          },
          "fs_type": {
            "type": "string",
            "description": "File system type, such as `ext4` or `xfs`."
          },
          "is_bind": {
            "type": "boolean",
            "description": "Whether the folder is mounted from the host."
          },
          "writable": {
            "type": "boolean",
            "description": "Whether the server can write to it."
          },
          "is_system": {
            "type": "boolean",
            "description": "True for the built-in storage folder."
          }
        }
      },
      "StorageMountTargets": {
        "type": "object",
        "required": [
          "default_path",
          "extra_mount_prefix",
          "targets"
        ],
        "properties": {
          "default_path": {
            "type": "string",
            "description": "The built-in storage folder, `/app/storage`."
          },
          "extra_mount_prefix": {
            "type": "string",
            "description": "Where extra storage folders are mounted, `/mnt/dew`."
          },
          "targets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StorageMountTarget"
            }
          }
        }
      },
      "SsoStatus": {
        "type": "object",
        "required": [
          "sso_enabled",
          "oidc_available",
          "saml_available",
          "saml_error",
          "connection_count"
        ],
        "properties": {
          "sso_enabled": {
            "type": "boolean",
            "description": "Whether an active single sign-on connection exists."
          },
          "oidc_available": {
            "type": "boolean",
            "description": "Always true."
          },
          "saml_available": {
            "type": "boolean",
            "description": "Whether SAML sign-in can be used on this server."
          },
          "saml_error": {
            "type": "string",
            "description": "Why SAML isn't available. Empty when it is."
          },
          "connection_count": {
            "type": "integer"
          }
        }
      },
      "SsoConnection": {
        "type": "object",
        "description": "A single sign-on connection to an identity provider. Client secrets and SCIM tokens are never returned, only whether one is saved.",
        "required": [
          "id",
          "name",
          "provider_type",
          "provider",
          "client_secret_set",
          "email_domains",
          "is_active",
          "allow_user_creation",
          "scim_enabled",
          "scim_bearer_token_set",
          "enforce_mode",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "description": "Left out when empty."
          },
          "provider_type": {
            "type": "string",
            "enum": [
              "saml",
              "oidc"
            ]
          },
          "provider": {
            "type": "string",
            "enum": [
              "entra",
              "okta",
              "google",
              "generic"
            ],
            "description": "The identity provider product."
          },
          "oidc_issuer_url": {
            "type": "string",
            "description": "OIDC only."
          },
          "oidc_client_id": {
            "type": "string",
            "description": "OIDC only."
          },
          "client_secret_set": {
            "type": "boolean",
            "description": "OIDC only: whether a client secret is saved. The secret itself is never returned."
          },
          "saml_metadata_url": {
            "type": "string",
            "description": "SAML only: where the identity provider's metadata is fetched from."
          },
          "saml_metadata_raw": {
            "type": "string",
            "description": "SAML only: identity provider metadata XML pasted by the admin."
          },
          "saml_additional_cert": {
            "type": "string",
            "description": "SAML only: an extra identity provider signing certificate, exactly as entered by the admin."
          },
          "saml_idp_sso_url": {
            "type": "string",
            "description": "SAML only: the identity provider's sign-in URL."
          },
          "saml_idp_entity_id": {
            "type": "string",
            "description": "SAML only."
          },
          "saml_idp_cert_count": {
            "type": "integer",
            "description": "SAML only: number of identity provider signing certificates."
          },
          "saml_idp_cert_expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "SAML only: when the first identity provider signing certificate expires."
          },
          "saml_certificates": {
            "type": "array",
            "description": "SAML only: every identity provider signing certificate Dew accepts, including the one kept after **Update certificate**.",
            "items": {
              "type": "object",
              "properties": {
                "expires_at": {
                  "type": "string",
                  "format": "date-time"
                },
                "additional": {
                  "type": "boolean",
                  "description": "The certificate kept next to its replacement. Dew removes it when it expires."
                }
              },
              "required": [
                "expires_at",
                "additional"
              ]
            }
          },
          "saml_attr_email": {
            "type": "string",
            "description": "SAML only: attribute that holds the email address."
          },
          "saml_attr_first_name": {
            "type": "string"
          },
          "saml_attr_last_name": {
            "type": "string"
          },
          "saml_attr_user_id": {
            "type": "string"
          },
          "email_domains": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Email domains that sign in through this connection."
          },
          "is_active": {
            "type": "boolean"
          },
          "allow_user_creation": {
            "type": "boolean",
            "description": "Whether new users are created on their first sign-in."
          },
          "scim_enabled": {
            "type": "boolean",
            "description": "Whether users are provisioned through SCIM."
          },
          "scim_bearer_token_set": {
            "type": "boolean",
            "description": "Whether a SCIM token exists. The token itself is never returned."
          },
          "enforce_mode": {
            "type": "string",
            "enum": [
              "optional",
              "required"
            ],
            "description": "`required`: users on the connection's email domains can't sign in with a password. `optional`: they can."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "sp_acs_url": {
            "type": "string",
            "description": "SAML only: the reply (ACS) URL to register with the identity provider. Left out until a primary domain exists."
          },
          "sp_entity_id": {
            "type": "string",
            "description": "SAML only: the entity ID to register with the identity provider."
          },
          "sp_metadata_url": {
            "type": "string",
            "description": "SAML only: this server's metadata URL."
          },
          "oidc_redirect_url": {
            "type": "string",
            "description": "OIDC only: the redirect URL to register with the identity provider."
          },
          "scim_base_url": {
            "type": "string",
            "description": "The SCIM base URL to give the identity provider."
          }
        }
      },
      "SsoConnectionDeleteImpact": {
        "type": "object",
        "required": [
          "connection_id",
          "attached_user_count",
          "active_user_count",
          "inactive_user_count"
        ],
        "properties": {
          "connection_id": {
            "type": "string"
          },
          "attached_user_count": {
            "type": "integer",
            "description": "Users who sign in through this connection."
          },
          "active_user_count": {
            "type": "integer"
          },
          "inactive_user_count": {
            "type": "integer"
          }
        }
      },
      "SsoEnforcementImpact": {
        "type": "object",
        "required": [
          "affected_user_count"
        ],
        "properties": {
          "affected_user_count": {
            "type": "integer",
            "description": "Active users on the connection's email domains who have a password and would no longer be able to sign in with it. Break-glass accounts are not counted."
          }
        }
      },
      "SsoEvent": {
        "type": "object",
        "required": [
          "id",
          "event_type",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "connection_id": {
            "type": "string",
            "description": "Left out when empty."
          },
          "event_type": {
            "type": "string",
            "enum": [
              "login",
              "login_failed",
              "user_provisioned",
              "user_linked",
              "scim_provision",
              "scim_deprovision",
              "scim_group_update"
            ]
          },
          "user_email": {
            "type": "string",
            "description": "Left out when empty."
          },
          "external_id": {
            "type": "string",
            "description": "The user's ID at the identity provider. Left out when empty."
          },
          "details": {
            "type": "object",
            "additionalProperties": true,
            "description": "More about the event, such as `reason` and `error` for a refused sign-in, `action` and `user_id` for a sign-in, or `group_id` and `group_name` for a SCIM group change."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AuditEvent": {
        "type": "object",
        "description": "One audit event. The audit log, its export, the audit feed, the activity feed and the `audit.log` file on the server all use this same record. Optional fields are left out when they have no value.",
        "required": [
          "id",
          "event_id",
          "timestamp",
          "event_type",
          "category",
          "outcome",
          "severity",
          "description",
          "actor"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "description": "Increasing number, assigned in the order events are saved. The feed cursor. Gaps are normal and never mean an event was deleted."
          },
          "event_id": {
            "type": "string",
            "format": "uuid",
            "description": "Stable across every way of reading the audit log. Deduplicate on it."
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "When the action happened: UTC, always with six fraction digits, such as `2026-09-25T14:03:11.120000Z`."
          },
          "event_type": {
            "type": "string",
            "description": "`<object>.<action>`, such as `file.downloaded`. The full list is at `GET /api/admin/audit-logs/event-types`.",
            "example": "file.downloaded"
          },
          "category": {
            "type": "string",
            "description": "The `<object>` part of `event_type`, for grouping.",
            "example": "file"
          },
          "outcome": {
            "type": "string",
            "enum": [
              "success",
              "failure"
            ],
            "description": "`failure` for an attempt that was refused."
          },
          "reason": {
            "type": "string",
            "description": "Why an attempt failed, or why the system acted, as a snake_case code such as `wrong_password` or `expired`."
          },
          "severity": {
            "type": "string",
            "enum": [
              "info",
              "warn"
            ],
            "description": "Fixed per event type; a failure is at least `warn`."
          },
          "description": {
            "type": "string",
            "description": "The event's label, such as \"File downloaded\" (the failure label for failures)."
          },
          "actor": {
            "type": "object",
            "description": "Who did it.",
            "required": [
              "type"
            ],
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "user",
                  "integration",
                  "idp",
                  "external",
                  "system"
                ],
                "description": "`user` (a person, also through their own personal token), `integration` (a service account, through one of its tokens), `idp` (user provisioning by a single sign-on connection), `external` (someone outside the app: a link recipient, an uploader, a caller presenting a token) or `system` (a background job, or a recovery command run on the server)."
              },
              "id": {
                "type": "string",
                "description": "User ID (`user`), service account ID (`integration`) or single sign-on connection ID (`idp`)."
              },
              "email": {
                "type": "string",
                "description": "The user's email. For `external`, the address a recipient proved or an uploader gave. On a failed sign-in, the address that was typed: a claim, not a verified identity."
              },
              "name": {
                "type": "string",
                "description": "Service account name, single sign-on connection name, or an uploader's name."
              }
            }
          },
          "target": {
            "type": "object",
            "description": "What was acted on. Left out when the event has no target.",
            "required": [
              "type"
            ],
            "properties": {
              "type": {
                "type": "string",
                "example": "file"
              },
              "id": {
                "type": "string",
                "description": "For `file.*` events, the link ID. Anyone with a link ID can open the link: treat stored events as holding link credentials."
              },
              "name": {
                "type": "string",
                "description": "The name at the time of the event, kept after the target is deleted."
              }
            }
          },
          "domain": {
            "type": "string",
            "description": "The hostname of the domain a `file.*` or `file_request.*` event happened on. Left out on every other event, and on events saved before October 2026.",
            "example": "files.example.com"
          },
          "client_ip": {
            "type": "string",
            "description": "The client's address."
          },
          "user_agent": {
            "type": "string",
            "description": "The client's User-Agent header, at most 512 bytes."
          },
          "request_id": {
            "type": "string",
            "description": "Matches system log entries and access log lines. The reference shown with an error, such as `REF-a3f8b2c1`, is `REF-` plus its first 8 characters."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true,
            "description": "Event details; the keys for each event are listed in the event catalog, and a key keeps one JSON type across all events. `changes` holds updates as `{\"field\": {\"old\": …, \"new\": …}}`, with secret values shown as `[redacted]`. Actions taken through an API token add `token_name`; when a service account acts as a person, `on_behalf_of` holds that person's email."
          }
        },
        "example": {
          "id": 48213,
          "event_id": "3f6c2a1e-8b4d-4c7a-9e21-5d0f7b6a9c34",
          "timestamp": "2026-10-02T14:03:11.120000Z",
          "event_type": "file.downloaded",
          "category": "file",
          "outcome": "success",
          "severity": "info",
          "description": "File downloaded",
          "actor": {
            "type": "external",
            "email": "bob@example.com"
          },
          "target": {
            "type": "file",
            "id": "kT9xQ2aZ",
            "name": "Q4 invoices.pdf"
          },
          "domain": "files.example.com",
          "client_ip": "203.0.113.24",
          "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
          "request_id": "a3f8b2c1d4e5f60718293a4b5c6d7e8f",
          "metadata": {
            "via": "link",
            "size_bytes": 2483021,
            "owner_email": "anna@example.com"
          }
        }
      },
      "AuditEventPage": {
        "type": "object",
        "required": [
          "entries",
          "next_cursor",
          "has_more"
        ],
        "properties": {
          "entries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AuditEvent"
            },
            "description": "Newest first."
          },
          "next_cursor": {
            "type": "string",
            "description": "Pass as `cursor` to get the next page. Empty when `has_more` is false."
          },
          "has_more": {
            "type": "boolean",
            "description": "Whether older events match the filters."
          }
        }
      },
      "AuditFeedPage": {
        "type": "object",
        "required": [
          "entries",
          "next_after_id",
          "has_more"
        ],
        "properties": {
          "entries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AuditEvent"
            },
            "description": "Oldest first, every `id` above `after_id`."
          },
          "next_after_id": {
            "type": "integer",
            "format": "int64",
            "description": "The `id` of the last event returned, or the `after_id` you sent when nothing was returned. Store it and send it as `after_id` on the next call."
          },
          "has_more": {
            "type": "boolean",
            "description": "True when the page is full (`limit` events). Poll again right away while it is true; the next page can be empty."
          }
        }
      },
      "AuditEventType": {
        "type": "object",
        "required": [
          "event_type",
          "category",
          "severity",
          "label"
        ],
        "properties": {
          "event_type": {
            "type": "string",
            "example": "file.downloaded"
          },
          "category": {
            "type": "string",
            "example": "file"
          },
          "severity": {
            "type": "string",
            "enum": [
              "info",
              "warn"
            ]
          },
          "label": {
            "type": "string",
            "description": "The `description` of a successful event. Empty for events that only record refused attempts."
          },
          "failure_label": {
            "type": "string",
            "description": "The `description` of a refused attempt. Left out for events that are only recorded as successes."
          }
        }
      },
      "AuditCategory": {
        "type": "object",
        "required": [
          "category",
          "label"
        ],
        "properties": {
          "category": {
            "type": "string",
            "example": "file"
          },
          "label": {
            "type": "string",
            "example": "Files and links"
          }
        }
      },
      "AuditCategoryCount": {
        "type": "object",
        "required": [
          "category",
          "count"
        ],
        "properties": {
          "category": {
            "type": "string"
          },
          "count": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "SystemLogEntry": {
        "type": "object",
        "required": [
          "id",
          "timestamp",
          "level",
          "message"
        ],
        "description": "One warning or error the server logged. Optional fields are left out when they have no value.",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          },
          "level": {
            "type": "string",
            "enum": [
              "warn",
              "error"
            ]
          },
          "message": {
            "type": "string"
          },
          "component": {
            "type": "string",
            "description": "The part of the server that logged it, such as `storage` or `email`."
          },
          "error_code": {
            "type": "string",
            "description": "A code naming the failure, such as `FILE_WRITE`. The full list is at `GET /api/admin/system-logs/error-codes`."
          },
          "request_id": {
            "type": "string",
            "description": "The request that failed. The reference shown with an error, such as `REF-a3f8b2c1`, is `REF-` plus its first 8 characters."
          },
          "attributes": {
            "type": "object",
            "additionalProperties": true,
            "description": "Further details logged with the message."
          },
          "stack_trace": {
            "type": "string"
          },
          "acknowledged_at": {
            "type": "string",
            "format": "date-time",
            "description": "When an admin marked the entry as handled. Left out until then."
          }
        }
      },
      "SystemLogPage": {
        "type": "object",
        "required": [
          "entries",
          "next_cursor",
          "has_more"
        ],
        "properties": {
          "entries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SystemLogEntry"
            },
            "description": "Newest first."
          },
          "next_cursor": {
            "type": "string",
            "description": "Pass as `cursor` to get the next page. Empty when `has_more` is false."
          },
          "has_more": {
            "type": "boolean"
          }
        }
      },
      "SystemLogComponentCount": {
        "type": "object",
        "required": [
          "component",
          "count"
        ],
        "properties": {
          "component": {
            "type": "string",
            "description": "`unknown` for entries logged without a component."
          },
          "count": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "Diagnostics": {
        "type": "object",
        "required": [
          "server_version",
          "os",
          "uptime_seconds",
          "postgres_version",
          "total_users",
          "total_files",
          "total_domains",
          "storage_providers",
          "sso_enabled",
          "log_level",
          "https_port",
          "public_https_port",
          "reverse_proxy",
          "trusted_proxies",
          "trusted_proxies_from_env"
        ],
        "properties": {
          "server_version": {
            "type": "string"
          },
          "os": {
            "type": "string",
            "description": "Operating system and architecture, such as `linux/amd64`."
          },
          "uptime_seconds": {
            "type": "integer",
            "format": "int64"
          },
          "postgres_version": {
            "type": "string"
          },
          "total_users": {
            "type": "integer",
            "format": "int64",
            "description": "People with an account; service accounts are not counted."
          },
          "total_files": {
            "type": "integer",
            "format": "int64"
          },
          "total_domains": {
            "type": "integer",
            "format": "int64"
          },
          "storage_providers": {
            "type": "array",
            "description": "The active storage providers.",
            "items": {
              "type": "object",
              "required": [
                "id",
                "name",
                "provider_type",
                "is_active"
              ],
              "properties": {
                "id": {
                  "type": "string",
                  "format": "uuid"
                },
                "name": {
                  "type": "string"
                },
                "provider_type": {
                  "type": "string",
                  "example": "s3"
                },
                "is_active": {
                  "type": "boolean"
                }
              }
            }
          },
          "saml_sp_cert": {
            "type": "object",
            "description": "The server's single sign-on (SAML) signing certificate. Left out when none is loaded.",
            "required": [
              "fingerprint",
              "expires_at"
            ],
            "properties": {
              "fingerprint": {
                "type": "string",
                "description": "SHA-256 fingerprint."
              },
              "expires_at": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "sso_enabled": {
            "type": "boolean",
            "description": "Whether any single sign-on connection is turned on."
          },
          "log_level": {
            "type": "string",
            "description": "The server's log level; `info` unless set otherwise."
          },
          "https_port": {
            "type": "string",
            "description": "The port the server listens on for HTTPS."
          },
          "public_https_port": {
            "type": "string",
            "description": "The HTTPS port people reach the server on."
          },
          "reverse_proxy": {
            "type": "string",
            "enum": [
              "trusted",
              "untrusted",
              "none",
              "checking"
            ],
            "description": "`trusted`: trusted proxies are configured. `untrusted`: proxied traffic came from a proxy that isn't trusted. `none`: no proxied traffic was seen. `checking`: still watching the first requests."
          },
          "trusted_proxies": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Networks whose forwarding headers the server trusts, in CIDR notation."
          },
          "trusted_proxies_from_env": {
            "type": "boolean",
            "description": "`true` when the trusted proxies come from `DEW_TRUSTED_PROXIES`, `false` when an admin trusted them on the System page."
          },
          "detected_proxy": {
            "type": "string",
            "description": "Set when `reverse_proxy` is `untrusted` and every proxied request came from one address: that address."
          },
          "detected_proxy_via_docker_gateway": {
            "type": "boolean",
            "description": "`true` when the detected proxy reaches the server through a Docker network's gateway, the address Docker also delivers other outside connections from."
          }
        }
      },
      "HealthCheck": {
        "type": "object",
        "description": "The current state of one area of the server.",
        "required": [
          "area",
          "status",
          "summary"
        ],
        "properties": {
          "area": {
            "type": "string",
            "enum": [
              "storage",
              "email",
              "certificates",
              "license",
              "errors"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "warn",
              "error"
            ],
            "description": "`warn` needs attention soon; `error` means something is not working now."
          },
          "summary": {
            "type": "string",
            "description": "A short description of the state, as the System page shows it."
          },
          "link": {
            "type": "string",
            "description": "The admin page that fixes the problem. Only set when `status` is not `ok`."
          }
        }
      },
      "SystemOverview": {
        "type": "object",
        "required": [
          "hostname",
          "checks",
          "stored_bytes",
          "update_check_enabled",
          "update_checked"
        ],
        "properties": {
          "hostname": {
            "type": "string",
            "description": "The primary domain's hostname."
          },
          "checks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HealthCheck"
            }
          },
          "stored_bytes": {
            "type": "integer",
            "format": "int64",
            "description": "Size of all stored files. A file shared through several links counts once."
          },
          "available_version": {
            "type": "string",
            "description": "A newer server version, when the update check found one."
          },
          "update_check_enabled": {
            "type": "boolean",
            "description": "Whether the server checks getdew.io once a day for a newer version."
          },
          "update_checked": {
            "type": "boolean",
            "description": "Whether getdew.io has answered the update check since the server started. Until then, no `available_version` does not mean the server is up to date."
          },
          "debug_logging_until": {
            "type": "string",
            "format": "date-time",
            "description": "When debug logging, turned on from the System page, turns itself off. Absent when it is off."
          }
        }
      },
      "AccessLogFile": {
        "type": "object",
        "required": [
          "name",
          "date",
          "size"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Pass as `file` to `GET /api/admin/access-logs`.",
            "example": "access-2026-10-01.log.gz"
          },
          "date": {
            "type": "string",
            "description": "`today` for the current file, otherwise the file's date as `YYYY-MM-DD`."
          },
          "size": {
            "type": "integer",
            "format": "int64",
            "description": "Size on disk in bytes (compressed for `.gz` files)."
          }
        }
      },
      "LicenseStatus": {
        "type": "object",
        "required": [
          "tier",
          "valid",
          "max_users",
          "activated",
          "trial",
          "needs_activation",
          "active_users",
          "pending_invites",
          "effective_users",
          "domain_count",
          "max_domains"
        ],
        "properties": {
          "tier": {
            "type": "string",
            "enum": [
              "Free",
              "Pro",
              "Enterprise"
            ]
          },
          "valid": {
            "type": "boolean"
          },
          "license_key": {
            "type": "string",
            "description": "The license key, masked to its first and last 4 characters. Empty without a key."
          },
          "max_users": {
            "type": "integer",
            "description": "Seats the license includes."
          },
          "machine_id": {
            "type": "string",
            "description": "This server's activation at the license service. Empty until activated."
          },
          "fingerprint": {
            "type": "string",
            "description": "The identity this server activates the license with."
          },
          "activated": {
            "type": "boolean"
          },
          "trial": {
            "type": "boolean"
          },
          "validation_error": {
            "type": "string",
            "description": "Why the last license check failed. Empty when it succeeded."
          },
          "needs_activation": {
            "type": "boolean",
            "description": "True when the license is held by an earlier installation, for example after restoring a backup or moving the server: activate it again from System > License."
          },
          "active_users": {
            "type": "integer",
            "format": "int64"
          },
          "pending_invites": {
            "type": "integer",
            "format": "int64"
          },
          "effective_users": {
            "type": "integer",
            "format": "int64",
            "description": "`active_users` plus `pending_invites`: what counts against `max_users`."
          },
          "domain_count": {
            "type": "integer",
            "format": "int64",
            "description": "Active domains."
          },
          "max_domains": {
            "type": "integer",
            "description": "`0` means unlimited."
          },
          "last_validated": {
            "type": "string",
            "format": "date-time",
            "description": "Left out before the first check."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "Left out when the license never expires."
          },
          "valid_until": {
            "type": "string",
            "format": "date-time",
            "description": "Set while a failed check is being tolerated: when licensed features stop unless it is resolved."
          },
          "grace_expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "Set while the server uses more than the license covers: when the changes in `enforcement` take effect."
          },
          "enforcement": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "What happens at `grace_expires_at`, such as \"1 extra domain will be turned off\"."
          }
        }
      },
      "AdminNotification": {
        "type": "object",
        "required": [
          "id",
          "category",
          "severity",
          "title",
          "message",
          "dismissed",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "category": {
            "type": "string",
            "description": "What the alert is about, such as `cert_expiry`, `storage`, `storage_health`, `license`, `license_grace`, `version`, `email_provider` or `api_token`."
          },
          "severity": {
            "type": "string",
            "enum": [
              "info",
              "warn",
              "error"
            ]
          },
          "title": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true,
            "description": "Details for some alerts, such as license grace periods."
          },
          "dismissed": {
            "type": "boolean",
            "description": "Always false here: dismissed alerts are not listed."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "The request is invalid; `message` says what to change.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "success": false,
              "error": "Bad Request",
              "message": "Choose an expiry date in the future."
            }
          }
        }
      },
      "Unauthorized": {
        "description": "The token is missing, wrong, revoked or expired.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "success": false,
              "error": "Unauthorized",
              "message": "Invalid or missing credentials"
            }
          }
        }
      },
      "Forbidden": {
        "description": "The token lacks the permission, or may not reach this item.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "success": false,
              "error": "ScopeMissing",
              "message": "This API token doesn't have permission for this action."
            }
          }
        }
      },
      "NotFound": {
        "description": "No such item, or not one this token can reach.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "success": false,
              "error": "Not Found",
              "message": "File not found"
            }
          }
        }
      },
      "ServerError": {
        "description": "Something failed on the server. `error` is an error code and `ref` a reference to quote to your admin, who can find it in the system logs.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "success": false,
              "error": "FILE_LIST",
              "message": "Failed to list files",
              "ref": "REF-a3f8b2c1"
            }
          }
        }
      }
    }
  },
  "security": [
    {
      "token": []
    }
  ],
  "paths": {
    "/api/file": {
      "post": {
        "operationId": "uploadFile",
        "summary": "Upload a file",
        "description": "Uploads one file in a single multipart request and creates its shared link. Put the link settings fields before the `file` part: fields after it are ignored. For large files, resumable uploads or several files behind one link, use Start an upload instead. Email recipients can't be set here; add them afterwards with Update link settings.",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "token": [
              "files:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "The domain for the shared link. It must be active and one you may use. Defaults to the domain you call the API on."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "link_type": {
                    "type": "string",
                    "enum": [
                      "public",
                      "protected",
                      "private",
                      "onetime"
                    ],
                    "default": "public",
                    "description": "Who can open the shared link. See Update link settings."
                  },
                  "protection_method": {
                    "type": "string",
                    "enum": [
                      "password",
                      "sms",
                      "email"
                    ],
                    "description": "Required when `link_type` is `protected`."
                  },
                  "password": {
                    "type": "string",
                    "description": "Password links: the password."
                  },
                  "auto_generate": {
                    "type": "string",
                    "enum": [
                      "true"
                    ],
                    "description": "Password links: `true` generates a password instead. The response returns a generated password once, as `generated_password`."
                  },
                  "phone_number": {
                    "type": "string",
                    "description": "SMS links: the full international number, such as `+15551234567`."
                  },
                  "country_code": {
                    "type": "string",
                    "description": "SMS links: ISO 3166-1 alpha-2 country, such as `US`. Used for display only."
                  },
                  "allowlist_id": {
                    "type": "string",
                    "description": "Required for `private` links: an allowlist available on the domain."
                  },
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "The file. Its part's file name becomes the file's name (at most 1020 bytes) and its part's `Content-Type` the file's type. Must be the last part."
                  }
                }
              },
              "encoding": {
                "file": {
                  "contentType": "application/octet-stream"
                }
              }
            }
          },
          "description": "Text fields are read up to 1024 bytes each."
        },
        "responses": {
          "200": {
            "description": "The file was uploaded.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/FileUploadResult"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "q7Rk2LmZ",
                    "url": "https://files.example.com/f/q7Rk2LmZ",
                    "formatted_text": "https://files.example.com/f/q7Rk2LmZ",
                    "filename": "report.pdf",
                    "filesize": 1048576,
                    "expires_at": "2026-11-03T09:15:00Z"
                  },
                  "message": "Upload successful"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, the domain is not one you may use (`Not allowed to use this domain`), or the user's account is unlicensed (`Unlicensed`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Forbidden",
                  "message": "Not allowed to use this domain"
                }
              }
            }
          },
          "413": {
            "description": "The file is larger than the domain allows.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Payload Too Large",
                  "message": "File too large"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/file/{filename}": {
      "put": {
        "operationId": "uploadFileRaw",
        "summary": "Upload a file from the request body",
        "description": "Uploads one file sent as the raw request body and creates its shared link. Link settings go in the query string. Set `Content-Type` to the file's type; without it the file is stored as `application/octet-stream`. Email recipients can't be set here; add them afterwards with Update link settings.",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "token": [
              "files:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "filename",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file's name, URL-encoded, at most 1020 bytes."
          },
          {
            "name": "domain",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "The domain for the shared link. It must be active and one you may use. Defaults to the domain you call the API on."
          },
          {
            "name": "link_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "public",
                "protected",
                "private",
                "onetime"
              ],
              "default": "public"
            },
            "description": "Who can open the shared link. See Update link settings."
          },
          {
            "name": "protection_method",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "password",
                "sms",
                "email"
              ]
            },
            "description": "Required when `link_type` is `protected`."
          },
          {
            "name": "password",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Password links: the password."
          },
          {
            "name": "auto_generate",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "true"
              ]
            },
            "description": "Password links: `true` generates a password instead. The response returns a generated password once, as `generated_password`."
          },
          {
            "name": "phone_number",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "SMS links: the full international number, such as `+15551234567`."
          },
          {
            "name": "country_code",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "SMS links: ISO 3166-1 alpha-2 country, such as `US`. Used for display only."
          },
          {
            "name": "allowlist_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required for `private` links: an allowlist available on the domain."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/octet-stream": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          },
          "description": "The file's bytes."
        },
        "responses": {
          "200": {
            "description": "The file was uploaded.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/FileUploadResult"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "q7Rk2LmZ",
                    "url": "https://files.example.com/f/q7Rk2LmZ",
                    "formatted_text": "https://files.example.com/f/q7Rk2LmZ",
                    "filename": "report.pdf",
                    "filesize": 1048576,
                    "expires_at": "2026-11-03T09:15:00Z"
                  },
                  "message": "Upload successful"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, the domain is not one you may use (`Not allowed to use this domain`), or the user's account is unlicensed (`Unlicensed`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Unlicensed",
                  "message": "Your account is unlicensed. Contact your administrator to restore upload access."
                }
              }
            }
          },
          "413": {
            "description": "The file is larger than the domain allows.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Payload Too Large",
                  "message": "File too large"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/file/{id}": {
      "delete": {
        "operationId": "deleteFile",
        "summary": "Delete a file",
        "description": "Permanently deletes a file you own and its shared link. Files received through a file request are deleted from the request instead.",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "token": [
              "files:delete"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file's ID, as returned when it was uploaded or listed."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "responses": {
          "200": {
            "description": "The file was deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true,
                  "message": "File deleted"
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid, or the file was received through a file request (manage it from the request instead).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Files received through a request are managed from the request. Open it to share or delete them."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the file belongs to someone else.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Forbidden",
                  "message": "You do not have permission to delete this file"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/file/{id}/info": {
      "get": {
        "operationId": "getFile",
        "summary": "Get a file",
        "description": "Returns a file you own. A file that belongs to someone else, or whose link has expired, is not found.",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "token": [
              "files:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file's ID, as returned when it was uploaded or listed."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "responses": {
          "200": {
            "description": "The file.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/FileInfo"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "q7Rk2LmZ",
                    "name": "report.pdf",
                    "size": 1048576,
                    "mime_type": "application/pdf",
                    "owner_id": "6f1c2a9e-4b7d-4e2a-9c3f-1d8e5b7a2c40",
                    "downloads": 3,
                    "created_at": "2026-10-04T09:15:00.123456Z",
                    "expires_at": "2026-11-03T09:15:00Z",
                    "domain_hostname": "files.example.com"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/file/{id}/link-settings": {
      "get": {
        "operationId": "getLinkSettings",
        "summary": "Get link settings",
        "description": "Returns who can open a file's shared link: its link type and, depending on the type, the phone number, allowlist, invited email addresses or whether a one-time link was used. Passwords are never returned.",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "token": [
              "files:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file's ID, as returned when it was uploaded or listed."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "responses": {
          "200": {
            "description": "The link settings.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/LinkSettings"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "file_id": "q7Rk2LmZ",
                    "link_type": "protected",
                    "protection_method": "email",
                    "email_recipients": [
                      {
                        "id": "er_3f9a1c7b2d4e6f80",
                        "email": "anna@example.com",
                        "invitation_sent_at": "2026-10-04T09:16:02Z",
                        "invitation_failed": false
                      },
                      {
                        "id": "er_8b2e4d6f0a1c3e57",
                        "email": "bob@example.com",
                        "invitation_failed": true
                      }
                    ],
                    "email_message": "Here are the signed contracts."
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the file belongs to someone else.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Forbidden",
                  "message": "You do not have permission to view this file's settings"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateLinkSettings",
        "summary": "Update link settings",
        "description": "Changes who can open a file's shared link. Send the full settings for the link type; `link_type` is required. New email recipients get an invitation email; switching to `onetime` makes a used link work again. People who already opened a protected link must unlock it again when its password, phone number or type changes.",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "token": [
              "files:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file's ID, as returned when it was uploaded or listed."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LinkSettingsUpdate"
              },
              "examples": {
                "password": {
                  "summary": "Protect with a password",
                  "value": {
                    "link_type": "protected",
                    "protection_method": "password",
                    "password": "harbor-lantern-42"
                  }
                },
                "email": {
                  "summary": "Invite people by email",
                  "value": {
                    "link_type": "protected",
                    "protection_method": "email",
                    "email_recipients": [
                      {
                        "email": "anna@example.com"
                      },
                      {
                        "email": "bob@example.com"
                      }
                    ],
                    "email_message": "Here are the signed contracts."
                  }
                },
                "public": {
                  "summary": "Make the link public",
                  "value": {
                    "link_type": "public"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The link settings were saved.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "description": "Present only when Dew generated a password.",
                          "properties": {
                            "generated_password": {
                              "type": "string",
                              "description": "The link's password, when you asked Dew to generate one (`auto_generate` without a password). This is the only time it is returned."
                            }
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "message": "Link settings updated"
                }
              }
            }
          },
          "400": {
            "description": "The settings are invalid (for example `Choose who can open the link.` when `link_type` is missing, `Password is required`, `Phone number is required`, `SMS protection is not available for this domain`, `Allowlist not available for this domain`, `Invalid email address: …`), or the file was received through a file request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Protection method is required for protected links"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the file belongs to someone else.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Forbidden",
                  "message": "You do not have permission to modify this file's settings"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/file/{id}/resend-invitations": {
      "post": {
        "operationId": "resendLinkInvitations",
        "summary": "Resend invitations",
        "description": "Emails the invitations of an email-protected link again. Each resent invitation carries a new link, so the one the person already has stops working; use `failed_only=true` to resend only invitations that couldn't be sent. You can resend once every 30 seconds.",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "token": [
              "files:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file's ID, as returned when it was uploaded or listed."
          },
          {
            "name": "failed_only",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "`true` resends only invitations that couldn't be sent."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "responses": {
          "200": {
            "description": "The invitations are being sent.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {
                            "queued": {
                              "type": "integer",
                              "description": "How many invitations are being sent."
                            }
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "queued": 2
                  },
                  "message": "Invitations resending"
                }
              }
            }
          },
          "400": {
            "description": "The link is not email-protected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "This link is not email-protected"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the file belongs to someone else.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Forbidden",
                  "message": "You do not have permission to manage this file"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "description": "Invitations were resent less than 30 seconds ago. Wait the number of seconds in `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Too Many Requests",
                  "message": "Invitations were just resent. Please wait a moment before trying again."
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait."
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/file/{id}/download-receipt": {
      "put": {
        "operationId": "setDownloadReceipt",
        "summary": "Turn download receipts on or off",
        "description": "Turns on or off the email the owner gets the first time someone downloads the file through its shared link. The email is sent once; turn the receipt on again to get another. For a service account, the email goes to its contact address, and without one nothing is sent.",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "token": [
              "files:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file's ID, as returned when it was uploaded or listed."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "enabled": {
                    "type": "boolean",
                    "default": false,
                    "description": "`true` turns the receipt on."
                  }
                }
              },
              "example": {
                "enabled": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The setting was saved.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {
                            "download_receipt": {
                              "type": "boolean"
                            }
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "download_receipt": true
                  },
                  "message": "Download receipt updated"
                }
              }
            }
          },
          "400": {
            "description": "The body is not valid JSON, or email isn't set up on the server.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Email isn't set up on this server, so download receipts can't be sent."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the file belongs to someone else.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Forbidden",
                  "message": "Not authorized"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/file/{id}/expiry": {
      "put": {
        "operationId": "updateFileExpiry",
        "summary": "Change when a link expires",
        "description": "Sets when a file's shared link expires. The date must be in the future and within the domain's maximum link lifetime (`max_expiry_at` in List files). Only an admin signed in to the web app can remove the expiry with `null`, so API tokens always send a date.",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "token": [
              "files:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file's ID, as returned when it was uploaded or listed."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "expires_at": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date-time",
                    "description": "The new expiry. `null` (no expiry) is refused under an API token."
                  }
                }
              },
              "example": {
                "expires_at": "2026-12-31T23:00:00Z"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The expiry was saved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true,
                  "message": "Expiry date updated"
                }
              }
            }
          },
          "400": {
            "description": "The date is missing (`null`), in the past (`Expiry date must be in the future`) or beyond the domain's maximum, the body is not valid JSON, or the file was received through a file request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Expiry date exceeds the maximum link lifetime for this domain"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the file belongs to someone else.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Forbidden",
                  "message": "Not authorized"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/files": {
      "get": {
        "operationId": "listFiles",
        "summary": "List files",
        "description": "Lists the files you own with their shared links, newest first by default, a page at a time. Files received through file requests are not listed. To get the next page, pass `cursor_id` and the cursor for your sort from the last file on the page; a page with fewer than `limit` files is the last.",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "token": [
              "files:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 15
            },
            "description": "Files per page. Values outside 1 to 100 return 15."
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only files whose name contains this text, ignoring case."
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "created_at",
                "name",
                "expires_at"
              ],
              "default": "created_at"
            },
            "description": "Sort field."
          },
          {
            "name": "order",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ]
            },
            "description": "Sort direction for `name` (default `asc`) and `expires_at` (default `asc`, links that never expire last). `created_at` is always newest first."
          },
          {
            "name": "access_types",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated link kinds to include: `public`, `password`, `sms`, `email`, `private`, `onetime`. Unknown values are ignored."
          },
          {
            "name": "cursor_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Next page: the `id` of the last file on the previous page, together with the cursor for the sort in use."
          },
          {
            "name": "cursor_ts",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Next page when sorting by `created_at`: the last file's `created_at`, unchanged."
          },
          {
            "name": "cursor_name",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Next page when sorting by `name`: the last file's `name`."
          },
          {
            "name": "cursor_expires",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Next page when sorting by `expires_at`: the last file's `expires_at`, unchanged."
          },
          {
            "name": "cursor_expires_null",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            },
            "description": "Next page when sorting by `expires_at` and the last file never expires: `1`."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of files.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/FileListItem"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "q7Rk2LmZ",
                      "name": "report.pdf",
                      "size": 1048576,
                      "url": "https://files.example.com/f/q7Rk2LmZ",
                      "formatted_text": "https://files.example.com/f/q7Rk2LmZ",
                      "downloads": 3,
                      "created_at": "2026-10-04T09:15:00.123456Z",
                      "expires_at": "2026-11-03T09:15:00Z",
                      "max_expiry_at": "2027-10-04T09:15:00.123456Z",
                      "link_type": "protected",
                      "protection_method": "password",
                      "domain_hostname": "files.example.com",
                      "download_receipt": false
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/file/{id}/download": {
      "get": {
        "operationId": "downloadFile",
        "summary": "Download a file",
        "description": "Downloads a file you own, whatever its link settings, without counting as a download of its shared link. On storage that serves downloads directly, the answer is a redirect to a temporary storage URL; follow it. Range requests are supported for resuming.",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "token": [
              "files:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file's ID, as returned when it was uploaded or listed."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "responses": {
          "200": {
            "description": "The file's bytes, with the file's own content type.",
            "headers": {
              "Content-Disposition": {
                "schema": {
                  "type": "string"
                },
                "description": "`attachment` with the file's name, such as `attachment; filename=\"report.pdf\"`."
              },
              "Accept-Ranges": {
                "schema": {
                  "type": "string"
                },
                "description": "`bytes`: send a `Range` header to resume."
              }
            },
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "206": {
            "description": "The requested byte range. A request for several ranges at once gets the whole file instead.",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "302": {
            "description": "Download from the URL in `Location`. It stays valid as long as the file takes to download at 1 MiB/s, at least 5 minutes and at most 24 hours.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the file belongs to someone else.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Forbidden",
                  "message": "Not your file"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "description": "The file couldn't be read from storage (`FILE_BLOB_MISSING` when it is gone, `FILE_READ` otherwise). Quote `ref` to your admin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "FILE_BLOB_MISSING",
                  "message": "Failed to retrieve file",
                  "ref": "REF-a3f8b2c1"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/files": {
      "get": {
        "operationId": "listAllFiles",
        "summary": "List files on your domains",
        "description": "Service account tokens only. Lists every user's files on the service account's domains, with their owners and shared links, a page at a time. Files received through file requests are not listed. Paging works as in List files.",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "token": [
              "files:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 15
            },
            "description": "Files per page. Values outside 1 to 100 return 15."
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only files whose name contains this text, ignoring case."
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "created_at",
                "name",
                "expires_at",
                "username"
              ],
              "default": "created_at"
            },
            "description": "Sort field. `username` sorts by the owner's display name."
          },
          {
            "name": "order",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ]
            },
            "description": "Sort direction for `name`, `expires_at` and `username` (default `asc`). `created_at` is always newest first."
          },
          {
            "name": "owner_ids",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated user IDs: only their files."
          },
          {
            "name": "access_types",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated link kinds to include: `public`, `password`, `sms`, `email`, `private`, `onetime`. Unknown values are ignored."
          },
          {
            "name": "cursor_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Next page: the `id` of the last file on the previous page, together with the cursor for the sort in use."
          },
          {
            "name": "cursor_ts",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Next page when sorting by `created_at`: the last file's `created_at`, unchanged."
          },
          {
            "name": "cursor_name",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Next page when sorting by `name`: the last file's `name`."
          },
          {
            "name": "cursor_expires",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Next page when sorting by `expires_at`: the last file's `expires_at`, unchanged."
          },
          {
            "name": "cursor_expires_null",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            },
            "description": "Next page when sorting by `expires_at` and the last file never expires: `1`."
          },
          {
            "name": "cursor_username",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Next page when sorting by `username`: the last file's `owner_username`."
          }
        ],
        "responses": {
          "200": {
            "description": "A page of files.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/AdminFileListItem"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "q7Rk2LmZ",
                      "name": "report.pdf",
                      "size": 1048576,
                      "url": "https://files.example.com/f/q7Rk2LmZ",
                      "formatted_text": "https://files.example.com/f/q7Rk2LmZ",
                      "downloads": 3,
                      "created_at": "2026-10-04T09:15:00.123456Z",
                      "expires_at": "2026-11-03T09:15:00Z",
                      "max_expiry_at": "2027-10-04T09:15:00.123456Z",
                      "link_type": "protected",
                      "protection_method": "password",
                      "domain_hostname": "files.example.com",
                      "download_receipt": false,
                      "owner_username": "Anna Berg",
                      "owner_email": "anna@example.com"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "`Dew-Act-As` was sent; it can't be used here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Dew-Act-As can't be used for admin actions."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, is a personal token, or the request comes from an IP address outside the admin allowlist.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Forbidden",
                  "message": "Personal API tokens can't be used for admin actions."
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/upload-session": {
      "post": {
        "operationId": "createUploadSession",
        "summary": "Start an upload",
        "description": "Starts a resumable upload of one file, or of several files behind one link. The response's `artifact` says how to send the bytes: when `chunk_size` is `0`, send everything with Upload in one request; otherwise send `total_chunks` chunks with Upload a chunk, or straight to the bucket when `direct_upload` is `true` (Get upload URLs for chunks). Then Finish an upload creates the shared link.\n\nTo send several files behind one link, use `session_type` `multi` (or `folder` to keep folders): you write the files into one uncompressed ZIP archive, laid out as described under `session_type`, under the `entry_name` each file gets in the response, and upload that archive. A ZIP you already have can also be sent as a `single` upload.\n\nWhen you act as a user with `Dew-Act-As`, the upload belongs to them: send the same header on every later call for this upload session.",
        "tags": [
          "Uploads"
        ],
        "security": [
          {
            "token": [
              "files:write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UploadSessionCreate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The upload session was created.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/UploadSession"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "session_id": "Hn4Tz8Qa",
                    "expires_at": "2026-10-05T09:15:00Z",
                    "files": [
                      {
                        "session_file_id": "sf_Jx2kQ9vR4mT7wY1zA3bC5d",
                        "filename": "brief.pdf",
                        "entry_name": "brief.pdf",
                        "entry_index": 0
                      },
                      {
                        "session_file_id": "sf_Pq8nL3sV6hG0eK2rU9tW4x",
                        "filename": "budget.xlsx",
                        "entry_name": "budget.xlsx",
                        "entry_index": 1
                      }
                    ],
                    "artifact": {
                      "file_id": "Hn4Tz8Qa",
                      "size_bytes": 502881,
                      "chunk_size": 0,
                      "total_chunks": 0
                    },
                    "direct_upload": false,
                    "upload_limit_bps": 0
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid: for example an unknown `session_type`, no files, a `single` upload with more than one file, an inactive domain, a blocked file type, an unsafe `relative_path` or invalid link settings.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "The '.exe' file type has been blocked by your administrator."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, the domain is not one you may use (`Not allowed to use this domain`), or the user's account is unlicensed (`Unlicensed`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Forbidden",
                  "message": "Not allowed to use this domain"
                }
              }
            }
          },
          "413": {
            "description": "The upload is larger than the domain allows (`Total size exceeds limit (N GB)`), or larger than 5 TB on S3-compatible storage.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Payload Too Large",
                  "message": "Total size exceeds limit (100 GB)"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "The domain's storage is unavailable. Contact your admin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "STORAGE_PROVIDER_UNAVAILABLE",
                  "message": "Storage provider for this domain is not available. Contact your administrator.",
                  "ref": "REF-a3f8b2c1"
                }
              }
            }
          },
          "507": {
            "description": "The storage doesn't have enough free space for this upload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Insufficient Storage",
                  "message": "Not enough storage space for this upload"
                }
              }
            }
          }
        }
      }
    },
    "/api/upload-session/{session_id}": {
      "get": {
        "operationId": "getUploadSession",
        "summary": "Get an upload",
        "description": "Returns an upload session's state and plan, for example to resume after a restart. The files are not listed again. If the upload session was created with `Dew-Act-As`, send the same header here.",
        "tags": [
          "Uploads"
        ],
        "security": [
          {
            "token": [
              "files:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The upload session's ID (`session_id` from Start an upload)."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "responses": {
          "200": {
            "description": "The upload session.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/UploadSessionStatus"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "session_id": "Hn4Tz8Qa",
                    "status": "active",
                    "session_type": "single",
                    "total_files": 1,
                    "created_at": "2026-10-04T09:15:00Z",
                    "expires_at": "2026-10-05T09:15:00Z",
                    "artifact": {
                      "file_id": "Hn4Tz8Qa",
                      "size_bytes": 104857600,
                      "chunk_size": 16777216,
                      "total_chunks": 7
                    },
                    "artifact_status": "pending"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the upload session belongs to someone else.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Forbidden",
                  "message": "Not your session"
                }
              }
            }
          },
          "404": {
            "description": "No upload session with this ID.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "Session not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "delete": {
        "operationId": "cancelUploadSession",
        "summary": "Cancel an upload",
        "description": "Cancels an upload that hasn't finished and deletes everything uploaded for it, including chunks sent straight to the bucket. If the upload session was created with `Dew-Act-As`, send the same header here.",
        "tags": [
          "Uploads"
        ],
        "security": [
          {
            "token": [
              "files:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The upload session's ID (`session_id` from Start an upload)."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "responses": {
          "200": {
            "description": "The upload was canceled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true,
                  "message": "Session canceled"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the upload session belongs to someone else.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Forbidden",
                  "message": "Not your session"
                }
              }
            }
          },
          "404": {
            "description": "No upload session with this ID.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "Session not found"
                }
              }
            }
          },
          "409": {
            "description": "The upload is being finished or has finished. Delete the file instead.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Conflict",
                  "message": "Session is no longer cancelable"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/upload-session/{session_id}/add-files": {
      "post": {
        "operationId": "addUploadSessionFiles",
        "summary": "Add files to an upload",
        "description": "Adds more files to a `multi` or `folder` upload, for example when listing a large folder in batches. Only possible before any bytes of the archive are uploaded: write the archive from the plan this returns, which replaces the earlier one. If the upload session was created with `Dew-Act-As`, send the same header here.",
        "tags": [
          "Uploads"
        ],
        "security": [
          {
            "token": [
              "files:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The upload session's ID (`session_id` from Start an upload)."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "files"
                ],
                "properties": {
                  "files": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "$ref": "#/components/schemas/UploadSessionFileInput"
                    },
                    "description": "The files to add. Requests are capped at 4 MiB."
                  }
                }
              },
              "example": {
                "files": [
                  {
                    "filename": "notes.txt",
                    "relative_path": "docs/notes.txt",
                    "size_bytes": 1024,
                    "mime_type": "text/plain"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The files were added.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/UploadSessionFilesAdded"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "files": [
                      {
                        "session_file_id": "sf_Wm5cE1yH7kN3pB9sD2fJ6q",
                        "filename": "notes.txt",
                        "entry_name": "docs/notes.txt",
                        "entry_index": 2
                      }
                    ],
                    "artifact": {
                      "file_id": "Hn4Tz8Qa",
                      "size_bytes": 504079,
                      "chunk_size": 0,
                      "total_chunks": 0
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "No files, the upload is `single` or no longer active, a blocked file type, or an unsafe `relative_path`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Files can only be added to a multi-file or folder session"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the upload session belongs to someone else.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Forbidden",
                  "message": "Not your session"
                }
              }
            }
          },
          "404": {
            "description": "No upload session with this ID.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "Session not found"
                }
              }
            }
          },
          "409": {
            "description": "Bytes of the archive were already uploaded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Conflict",
                  "message": "Files cannot be added after the upload has started"
                }
              }
            }
          },
          "410": {
            "description": "The upload session expired. Start a new upload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "SessionExpired",
                  "message": "This upload has expired. Start it again."
                }
              }
            }
          },
          "413": {
            "description": "The upload is larger than the domain allows (`Total size exceeds limit (N GB)`), or larger than 5 TB on S3-compatible storage.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Payload Too Large",
                  "message": "Total size exceeds limit (100 GB)"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "507": {
            "description": "The storage doesn't have enough free space for this upload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Insufficient Storage",
                  "message": "Not enough storage space for this upload"
                }
              }
            }
          }
        }
      }
    },
    "/api/upload-session/{session_id}/files/{file_id}/chunk/{chunk_number}": {
      "patch": {
        "operationId": "uploadChunk",
        "summary": "Upload a chunk",
        "description": "Uploads one chunk of the planned bytes. Chunk `n` starts at byte `(n - 1) × chunk_size` and is `chunk_size` bytes long; the last chunk carries the rest. Chunks can be sent in parallel. Sending a chunk again replaces it, so retry any chunk that fails. If the upload session was created with `Dew-Act-As`, send the same header here.",
        "tags": [
          "Uploads"
        ],
        "security": [
          {
            "token": [
              "files:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The upload session's ID (`session_id` from Start an upload)."
          },
          {
            "name": "file_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The upload's `artifact.file_id`. It is always the same as `session_id`."
          },
          {
            "name": "chunk_number",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "description": "The chunk's number, from 1 to `total_chunks`."
          },
          {
            "name": "X-Chunk-Offset",
            "in": "header",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0
            },
            "description": "Where the chunk starts: `(chunk_number - 1) × chunk_size`."
          },
          {
            "name": "Content-Length",
            "in": "header",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "description": "The chunk's exact length. Chunked transfer encoding is not accepted."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/octet-stream": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          },
          "description": "The chunk's bytes."
        },
        "responses": {
          "200": {
            "description": "The chunk was stored.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {
                            "chunk_number": {
                              "type": "integer"
                            }
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "chunk_number": 3
                  }
                }
              }
            }
          },
          "400": {
            "description": "The chunk doesn't match the plan (number, offset or length), `X-Chunk-Offset` is missing, the upload goes in one request, `file_id` is not the upload's, or the upload is no longer active.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Chunk 3 must carry 16777216 bytes at offset 33554432"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the upload session belongs to someone else.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Forbidden",
                  "message": "Not your session"
                }
              }
            }
          },
          "404": {
            "description": "No upload session with this ID.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "Session not found"
                }
              }
            }
          },
          "409": {
            "description": "This chunk is still being uploaded by another request. Retry in a few seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Conflict",
                  "message": "Chunk is already being uploaded"
                }
              }
            }
          },
          "410": {
            "description": "The upload session expired. Start a new upload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "SessionExpired",
                  "message": "This upload has expired. Start it again."
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/upload-session/{session_id}/files/{file_id}/chunks": {
      "get": {
        "operationId": "listUploadedChunks",
        "summary": "List uploaded chunks",
        "description": "Returns which chunks the server already has, including chunks sent straight to the bucket. Use it to resume an interrupted upload: send only the missing chunks, then finish. If the upload session was created with `Dew-Act-As`, send the same header here.",
        "tags": [
          "Uploads"
        ],
        "security": [
          {
            "token": [
              "files:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The upload session's ID (`session_id` from Start an upload)."
          },
          {
            "name": "file_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The upload's `artifact.file_id`. It is always the same as `session_id`."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "responses": {
          "200": {
            "description": "The chunks received so far.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/UploadChunkProgress"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "session_file_id": "Hn4Tz8Qa",
                    "completed_chunks": [
                      1,
                      2,
                      3
                    ],
                    "uploaded_bytes": 50331648,
                    "total_bytes": 104857600,
                    "chunk_size": 16777216,
                    "total_chunks": 7
                  }
                }
              }
            }
          },
          "400": {
            "description": "`file_id` is not the upload's, or the upload is no longer active.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Session is not active"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the upload session belongs to someone else.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Forbidden",
                  "message": "Not your session"
                }
              }
            }
          },
          "404": {
            "description": "No upload session with this ID.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "Session not found"
                }
              }
            }
          },
          "410": {
            "description": "The upload session expired. Start a new upload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "SessionExpired",
                  "message": "This upload has expired. Start it again."
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/upload-session/{session_id}/files/{file_id}/fast": {
      "put": {
        "operationId": "uploadInOneRequest",
        "summary": "Upload in one request",
        "description": "Uploads all the planned bytes in one request, for uploads whose plan has `chunk_size` `0`. Send exactly `artifact.size_bytes` bytes: more is refused, and a different size makes finishing fail. If the upload session was created with `Dew-Act-As`, send the same header here.",
        "tags": [
          "Uploads"
        ],
        "security": [
          {
            "token": [
              "files:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The upload session's ID (`session_id` from Start an upload)."
          },
          {
            "name": "file_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The upload's `artifact.file_id`. It is always the same as `session_id`."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/octet-stream": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          },
          "description": "The file, or your ZIP archive for `multi` and `folder` uploads."
        },
        "responses": {
          "200": {
            "description": "The bytes were stored.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {
                            "uploaded_bytes": {
                              "type": "integer",
                              "format": "int64"
                            }
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "uploaded_bytes": 502881
                  }
                }
              }
            }
          },
          "400": {
            "description": "The upload must be sent in chunks, `file_id` is not the upload's, or the upload is no longer active.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "File must be uploaded in chunks"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the upload session belongs to someone else.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Forbidden",
                  "message": "Not your session"
                }
              }
            }
          },
          "404": {
            "description": "No upload session with this ID.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "Session not found"
                }
              }
            }
          },
          "410": {
            "description": "The upload session expired. Start a new upload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "SessionExpired",
                  "message": "This upload has expired. Start it again."
                }
              }
            }
          },
          "413": {
            "description": "More bytes were sent than planned.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Payload Too Large",
                  "message": "File exceeds declared size"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/upload-session/{session_id}/files/{file_id}/presign": {
      "post": {
        "operationId": "presignUploadParts",
        "summary": "Get upload URLs for chunks",
        "description": "When the upload session has `direct_upload: true`, returns URLs to `PUT` chunks straight to the storage bucket, up to 500 per request. Each URL accepts exactly its chunk's planned length and stops working after 6 hours; ask for URLs as you need them. Chunks sent this way and chunks sent with Upload a chunk can be mixed. If the upload session was created with `Dew-Act-As`, send the same header here.",
        "tags": [
          "Uploads"
        ],
        "security": [
          {
            "token": [
              "files:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The upload session's ID (`session_id` from Start an upload)."
          },
          {
            "name": "file_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The upload's `artifact.file_id`. It is always the same as `session_id`."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "part_numbers"
                ],
                "properties": {
                  "part_numbers": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 500,
                    "items": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "description": "Chunk numbers to get URLs for, from 1 to `total_chunks`."
                  }
                }
              },
              "example": {
                "part_numbers": [
                  1,
                  2,
                  3
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The URLs, by chunk number.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/UploadPartUrls"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "urls": {
                      "1": "https://bucket.s3.example.com/Hn4Tz8Qa?partNumber=1&uploadId=VXBsb2FkSWQ&X-Amz-Signature=3f2a",
                      "2": "https://bucket.s3.example.com/Hn4Tz8Qa?partNumber=2&uploadId=VXBsb2FkSWQ&X-Amz-Signature=9c1d",
                      "3": "https://bucket.s3.example.com/Hn4Tz8Qa?partNumber=3&uploadId=VXBsb2FkSWQ&X-Amz-Signature=b7e4"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Direct upload is not available for this domain, the upload is not sent in chunks, `part_numbers` is empty, has more than 500 numbers or a number out of range, `file_id` is not the upload's, or the upload is no longer active.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Direct upload is not available for this domain"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the upload session belongs to someone else.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Forbidden",
                  "message": "Not your session"
                }
              }
            }
          },
          "404": {
            "description": "No upload session with this ID.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "Session not found"
                }
              }
            }
          },
          "410": {
            "description": "The upload session expired. Start a new upload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "SessionExpired",
                  "message": "This upload has expired. Start it again."
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/upload-session/{session_id}/finalize": {
      "post": {
        "operationId": "finishUploadSession",
        "summary": "Finish an upload",
        "description": "Checks the uploaded bytes against the plan and creates the file and its shared link; for `multi` and `folder` uploads it also checks the archive's file list. Email-protected links send their invitations now. Calling it again after a lost response returns the same links; a `409 Finalizing` means it is still running, so ask again in a few seconds. If the upload session was created with `Dew-Act-As`, send the same header here.",
        "tags": [
          "Uploads"
        ],
        "security": [
          {
            "token": [
              "files:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The upload session's ID (`session_id` from Start an upload)."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Send `{}` when there is nothing to skip.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "skip_file_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "`multi` and `folder`: the `session_file_id` of files you left out of the archive's central directory because they couldn't be read. Their planned bytes must still be in the archive (as zeros), so its size doesn't change."
                  }
                }
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The upload is finished.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/UploadFinishResult"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "files": [],
                    "zip_file": {
                      "id": "Hn4Tz8Qa",
                      "url": "https://files.example.com/p/Hn4Tz8Qa",
                      "formatted_text": "https://files.example.com/p/Hn4Tz8Qa",
                      "filename": "Project files.zip",
                      "filesize": 502881,
                      "expires_at": "2026-11-03T09:15:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The body is not valid JSON, the upload is no longer active, or what was uploaded doesn't match the plan: a different size, an archive whose files differ from the ones listed, or nothing left to deliver. In those last cases the uploaded bytes are deleted; start a new upload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "The uploaded archive does not match the files that were registered"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the upload session belongs to someone else.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Forbidden",
                  "message": "Not your session"
                }
              }
            }
          },
          "404": {
            "description": "No upload session with this ID.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "Session not found"
                }
              }
            }
          },
          "409": {
            "description": "`Finalizing`: an earlier call is still finishing this upload; ask again in a few seconds. `Conflict`: nothing was uploaded; start a new upload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Finalizing",
                  "message": "This upload is still being finished. Try again in a moment."
                }
              }
            }
          },
          "410": {
            "description": "The upload session expired. Start a new upload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "SessionExpired",
                  "message": "This upload has expired. Start it again."
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/file-requests": {
      "post": {
        "operationId": "createFileRequest",
        "summary": "Create a file request",
        "description": "Creates a file request and emails each invited person their own upload link. The shared link is on unless you send `link_enabled: false` or your administrator has turned off shared links; a request without a shared link needs at least one invitee. Inviting people needs email set up for the domain. Under a service account token, the deadline must be within the domain's maximum link lifetime even when acting as an admin.",
        "tags": [
          "File requests"
        ],
        "security": [
          {
            "token": [
              "requests:write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "label",
                  "due_at"
                ],
                "properties": {
                  "label": {
                    "type": "string",
                    "maxLength": 120,
                    "description": "The title. Required; leading and trailing spaces are removed."
                  },
                  "message": {
                    "type": "string",
                    "maxLength": 1000,
                    "description": "Instructions for people sending files."
                  },
                  "recipient_emails": {
                    "type": "array",
                    "maxItems": 50,
                    "items": {
                      "type": "string"
                    },
                    "description": "People to invite. Duplicates and empty entries are ignored; `Name <address>` is accepted. Up to 50 different addresses."
                  },
                  "due_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "The deadline, in the future and within the domain's maximum link lifetime if your administrator set one."
                  },
                  "notify_mode": {
                    "type": "string",
                    "enum": [
                      "each",
                      "digest",
                      "off"
                    ],
                    "default": "each",
                    "description": "Email notifications to you: one per upload, a daily summary, or none."
                  },
                  "link_enabled": {
                    "type": "boolean",
                    "description": "Turn the shared link on or off. Defaults to on, or off when your administrator has turned off shared links."
                  },
                  "domain": {
                    "type": "string",
                    "description": "The domain to create the request on. Defaults to the domain you call the API on. The request's user must have access to it, and under `Dew-Act-As` so must the service account."
                  }
                }
              },
              "example": {
                "label": "Q3 receipts",
                "message": "Please send your receipts for July to September as PDFs.",
                "recipient_emails": [
                  "anna@example.com"
                ],
                "due_at": "2026-10-31T22:59:59Z",
                "notify_mode": "each"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The request was created.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "required": [
                            "file_request",
                            "failed_recipients"
                          ],
                          "properties": {
                            "file_request": {
                              "$ref": "#/components/schemas/FileRequest"
                            },
                            "failed_recipients": {
                              "type": "array",
                              "items": {
                                "type": "string",
                                "format": "email"
                              },
                              "description": "Always empty: the invitations go out after the response. A person the invitation couldn't reach gets `invite_failed_at` on the request."
                            }
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "message": "File request created",
                  "data": {
                    "file_request": {
                      "id": "aB3dE9kQ",
                      "creator_id": "6f1c2b3a-4d5e-4f60-8a7b-9c0d1e2f3a4b",
                      "label": "Q3 receipts",
                      "message": "Please send your receipts for July to September as PDFs.",
                      "domain_hostname": "files.example.com",
                      "created_at": "2026-10-01T09:00:00Z",
                      "due_at": "2026-10-31T22:59:59Z",
                      "deletes_at": "2027-01-29T22:59:59Z",
                      "link_enabled": true,
                      "notify_mode": "each",
                      "people": [
                        {
                          "id": "rcp_3f9c2a1b7d4e4f6a8b0c1d2e3f4a5b6c",
                          "email": "anna@example.com",
                          "source": "invite",
                          "email_verified": true,
                          "created_at": "2026-10-01T09:00:00Z",
                          "file_count": 0
                        }
                      ],
                      "file_count": 0,
                      "total_size": 0,
                      "new_upload_count": 0,
                      "link_count": 0,
                      "status": "open",
                      "link_url": "https://files.example.com/r/Hk82LmQp"
                    },
                    "failed_recipients": []
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission; the user's account is unlicensed; the user has no access to the domain; or shared links are turned off by your administrator and `link_enabled` is true.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "unlicensed": {
                    "value": {
                      "success": false,
                      "error": "Unlicensed",
                      "message": "Your account is unlicensed. Contact your administrator to restore upload access."
                    }
                  },
                  "domain": {
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "You don't have access to this domain."
                    }
                  },
                  "link_off": {
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Your administrator has turned off shared links."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "get": {
        "operationId": "listFileRequests",
        "summary": "List file requests",
        "description": "Lists the file requests the user owns, newest first, with their people and totals. Without `limit`, every request. With `limit`, a page at a time: for the next page, pass the last request's `created_at` and `id` as `cursor_ts` and `cursor_id`; a page shorter than `limit` is the last.",
        "tags": [
          "File requests"
        ],
        "security": [
          {
            "token": [
              "requests:read"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ActAs"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "closed"
              ]
            },
            "description": "Only open requests, or only closed ones (closed by hand or past their deadline). Both when left out."
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Matches the title, or the address or name of someone on the request."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            },
            "description": "Requests per page; above 100 counts as 100."
          },
          {
            "name": "cursor_ts",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "`created_at` of the last request on the previous page."
          },
          {
            "name": "cursor_id",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "`id` of the last request on the previous page."
          }
        ],
        "responses": {
          "200": {
            "description": "The user's file requests.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/FileRequest"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "aB3dE9kQ",
                      "creator_id": "6f1c2b3a-4d5e-4f60-8a7b-9c0d1e2f3a4b",
                      "label": "Q3 receipts",
                      "message": "Please send your receipts for July to September as PDFs.",
                      "domain_hostname": "files.example.com",
                      "created_at": "2026-10-01T09:00:00Z",
                      "due_at": "2026-10-31T22:59:59Z",
                      "deletes_at": "2027-01-29T22:59:59Z",
                      "link_enabled": true,
                      "notify_mode": "each",
                      "people": [
                        {
                          "id": "rcp_3f9c2a1b7d4e4f6a8b0c1d2e3f4a5b6c",
                          "email": "anna@example.com",
                          "source": "invite",
                          "email_verified": true,
                          "created_at": "2026-10-01T09:00:00Z",
                          "file_count": 3
                        },
                        {
                          "id": "rcp_8a7b6c5d4e3f4a1b9c2d3e4f5a6b7c8d",
                          "email": "bob@example.com",
                          "name": "Bob Jensen",
                          "source": "link",
                          "email_verified": true,
                          "created_at": "2026-10-02T14:12:00Z",
                          "file_count": 1
                        }
                      ],
                      "file_count": 4,
                      "total_size": 5242880,
                      "new_upload_count": 1,
                      "last_submitted_at": "2026-10-02T14:15:00Z",
                      "link_count": 0,
                      "status": "open",
                      "link_url": "https://files.example.com/r/Hk82LmQp"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/file-requests/{id}": {
      "get": {
        "operationId": "getFileRequest",
        "summary": "Get a file request",
        "description": "Returns one file request with its people, every upload it received and its latest activity. To list the files inside an upload of several files, use the contents endpoint.",
        "tags": [
          "File requests"
        ],
        "security": [
          {
            "token": [
              "requests:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file request's ID."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "responses": {
          "200": {
            "description": "The file request.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/FileRequestDetail"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "file_request": {
                      "id": "aB3dE9kQ",
                      "creator_id": "6f1c2b3a-4d5e-4f60-8a7b-9c0d1e2f3a4b",
                      "label": "Q3 receipts",
                      "message": "Please send your receipts for July to September as PDFs.",
                      "domain_hostname": "files.example.com",
                      "created_at": "2026-10-01T09:00:00Z",
                      "due_at": "2026-10-31T22:59:59Z",
                      "deletes_at": "2027-01-29T22:59:59Z",
                      "link_enabled": true,
                      "notify_mode": "each",
                      "people": [
                        {
                          "id": "rcp_3f9c2a1b7d4e4f6a8b0c1d2e3f4a5b6c",
                          "email": "anna@example.com",
                          "source": "invite",
                          "email_verified": true,
                          "created_at": "2026-10-01T09:00:00Z",
                          "file_count": 3
                        },
                        {
                          "id": "rcp_8a7b6c5d4e3f4a1b9c2d3e4f5a6b7c8d",
                          "email": "bob@example.com",
                          "name": "Bob Jensen",
                          "source": "link",
                          "email_verified": true,
                          "created_at": "2026-10-02T14:12:00Z",
                          "file_count": 1
                        }
                      ],
                      "file_count": 4,
                      "total_size": 5242880,
                      "new_upload_count": 1,
                      "last_submitted_at": "2026-10-02T14:15:00Z",
                      "link_count": 0,
                      "status": "open",
                      "link_url": "https://files.example.com/r/Hk82LmQp"
                    },
                    "uploads": [
                      {
                        "file_id": "Qw4Rt8Zn",
                        "name": "invoice-0912.pdf",
                        "size": 1048576,
                        "mime_type": "application/pdf",
                        "kind": "file",
                        "file_count": 1,
                        "sender_email": "bob@example.com",
                        "sender_name": "Bob Jensen",
                        "recipient_id": "rcp_8a7b6c5d4e3f4a1b9c2d3e4f5a6b7c8d",
                        "received_at": "2026-10-02T14:15:00Z",
                        "is_new": true,
                        "link_count": 0
                      },
                      {
                        "file_id": "Xy7Kp2Lm",
                        "name": "receipts.zip",
                        "size": 4194304,
                        "mime_type": "application/zip",
                        "kind": "archive",
                        "file_count": 3,
                        "sender_email": "anna@example.com",
                        "sender_message": "All three months are in here.",
                        "recipient_id": "rcp_3f9c2a1b7d4e4f6a8b0c1d2e3f4a5b6c",
                        "received_at": "2026-10-01T16:40:00Z",
                        "is_new": false,
                        "link_count": 0
                      }
                    ],
                    "activity": [
                      {
                        "event_type": "file_request.created",
                        "actor_email": "anna.owner@example.com",
                        "actor_name": "Anna Owner",
                        "target_name": "Q3 receipts",
                        "metadata": {
                          "domain": "files.example.com",
                          "link_enabled": true
                        },
                        "timestamp": "2026-10-01T09:00:00Z"
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such file request, or it belongs to someone else.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "File request not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "put": {
        "operationId": "updateFileRequest",
        "summary": "Update a file request",
        "description": "Changes a file request's title, instructions, deadline, email notifications or shared link, or closes or reopens it. Send only the fields to change. Closing the request or turning off the shared link stops uploads in progress. Reopening a request whose deadline has passed needs a new `due_at` in the same call. Turning the shared link back on keeps its address.",
        "tags": [
          "File requests"
        ],
        "security": [
          {
            "token": [
              "requests:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file request's ID."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "label": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 120,
                    "description": "The title. Can't be empty."
                  },
                  "message": {
                    "type": "string",
                    "maxLength": 1000,
                    "description": "Instructions for people sending files. An empty string removes them."
                  },
                  "due_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "A new deadline, in the future and within the domain's maximum link lifetime if your administrator set one."
                  },
                  "notify_mode": {
                    "type": "string",
                    "enum": [
                      "each",
                      "digest",
                      "off"
                    ]
                  },
                  "link_enabled": {
                    "type": "boolean",
                    "description": "Turn the shared link on or off. It can't be turned on while your administrator has turned off shared links."
                  },
                  "closed": {
                    "type": "boolean",
                    "description": "`true` closes the request, `false` reopens it."
                  }
                }
              },
              "example": {
                "due_at": "2026-11-15T22:59:59Z",
                "closed": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The request was updated.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "required": [
                            "file_request"
                          ],
                          "properties": {
                            "file_request": {
                              "$ref": "#/components/schemas/UpdatedFileRequest"
                            }
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "message": "File request updated",
                  "data": {
                    "file_request": {
                      "id": "aB3dE9kQ",
                      "creator_id": "6f1c2b3a-4d5e-4f60-8a7b-9c0d1e2f3a4b",
                      "label": "Q3 receipts",
                      "message": "Please send your receipts for July to September as PDFs.",
                      "domain_hostname": "files.example.com",
                      "created_at": "2026-10-01T09:00:00Z",
                      "due_at": "2026-11-15T22:59:59Z",
                      "deletes_at": "2027-02-13T22:59:59Z",
                      "link_enabled": true,
                      "notify_mode": "each"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or shared links are turned off by your administrator and `link_enabled` is true.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "link_off": {
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Your administrator has turned off shared links."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such file request, or it belongs to someone else.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "File request not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "delete": {
        "operationId": "deleteFileRequest",
        "summary": "Delete a file request",
        "description": "Permanently deletes a file request and every file received through it. Files still shared through links made from them stay until those links are gone. People's upload links stop working.",
        "tags": [
          "File requests"
        ],
        "security": [
          {
            "token": [
              "requests:delete"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file request's ID."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "responses": {
          "200": {
            "description": "The request was deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true,
                  "message": "File request deleted"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such file request, or it belongs to someone else.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "File request not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/file-requests/{id}/seen": {
      "post": {
        "operationId": "markFileRequestSeen",
        "summary": "Mark uploads as seen",
        "description": "Marks every upload on the request as seen, so `is_new` turns false and `new_upload_count` goes to 0.",
        "tags": [
          "File requests"
        ],
        "security": [
          {
            "token": [
              "requests:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file request's ID."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "responses": {
          "200": {
            "description": "The uploads are marked as seen.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such file request, or it belongs to someone else.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "File request not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/file-requests/{id}/people": {
      "post": {
        "operationId": "inviteToFileRequest",
        "summary": "Invite people",
        "description": "Invites people to an open file request and emails each their own upload link. Addresses already invited are skipped. A request can have up to 50 invitees. Needs email set up for the request's domain.",
        "tags": [
          "File requests"
        ],
        "security": [
          {
            "token": [
              "requests:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file request's ID."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "emails": {
                    "type": "array",
                    "maxItems": 50,
                    "items": {
                      "type": "string"
                    },
                    "description": "Addresses to invite. Duplicates and empty entries are ignored; `Name <address>` is accepted."
                  }
                }
              },
              "example": {
                "emails": [
                  "bob@example.com"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The new invitees. Their invitations go out after the response.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/FileRequestEmailResult"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "emails": [
                      "bob@example.com"
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such file request, or it belongs to someone else.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "File request not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/file-requests/{id}/people/{person_id}": {
      "put": {
        "operationId": "updateFileRequestPerson",
        "summary": "Change a person's email address",
        "description": "Corrects an invitee's email address on an open file request and sends the invitation to the new address. Their previous upload link stops working. Needs email set up for the request's domain.",
        "tags": [
          "File requests"
        ],
        "security": [
          {
            "token": [
              "requests:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file request's ID."
          },
          {
            "name": "person_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The person's ID, from `people` on the file request."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "description": "The new address. It can't be one already invited to the request."
                  }
                }
              },
              "example": {
                "email": "anna.berg@example.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The address was changed.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "required": [
                            "delivered"
                          ],
                          "properties": {
                            "delivered": {
                              "type": "boolean",
                              "description": "Whether the invitation email to the new address was delivered."
                            }
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "delivered": true
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such file request, or the person is no longer on it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "That person is no longer part of this request."
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "delete": {
        "operationId": "removeFileRequestPerson",
        "summary": "Remove a person",
        "description": "Removes a person from a file request. Their upload link stops working, including for an upload in progress. Files they already sent stay on the request.",
        "tags": [
          "File requests"
        ],
        "security": [
          {
            "token": [
              "requests:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file request's ID."
          },
          {
            "name": "person_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The person's ID, from `people` on the file request."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "responses": {
          "200": {
            "description": "The person was removed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such file request, or the person is no longer on it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "That person is no longer part of this request."
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/file-requests/{id}/remind": {
      "post": {
        "operationId": "remindFileRequest",
        "summary": "Send reminders",
        "description": "Emails selected invitees their upload link again, with an optional note. Only invitees can be reminded, and only while the request is open. One reminder call is allowed every 30 seconds per user.",
        "tags": [
          "File requests"
        ],
        "security": [
          {
            "token": [
              "requests:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file request's ID."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "person_ids"
                ],
                "properties": {
                  "person_ids": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "type": "string"
                    },
                    "description": "IDs of invitees to remind, from `people` on the request."
                  },
                  "note": {
                    "type": "string",
                    "maxLength": 500,
                    "description": "A note added to the reminder."
                  }
                }
              },
              "example": {
                "person_ids": [
                  "rcp_3f9c2a1b7d4e4f6a8b0c1d2e3f4a5b6c"
                ],
                "note": "Just a reminder: we need these by Friday."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The people being reminded. The reminders go out after the response.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/FileRequestEmailResult"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "emails": [
                      "anna@example.com"
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such file request, or it belongs to someone else.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "File request not found"
                }
              }
            }
          },
          "429": {
            "description": "A reminder was sent less than 30 seconds ago.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Too Many Requests",
                  "message": "Please wait a moment before sending another reminder."
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before trying again.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/file-requests/{id}/download": {
      "get": {
        "operationId": "downloadFileRequest",
        "summary": "Download everything received",
        "description": "Downloads every file the request received. When there is only one single-file upload you get that file; otherwise one ZIP.",
        "tags": [
          "File requests"
        ],
        "security": [
          {
            "token": [
              "requests:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file request's ID."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "responses": {
          "200": {
            "description": "The files. One single file comes as itself, and one file inside an upload as that file; anything else comes as a ZIP named after the request, with a folder per sender when several people sent files. A ZIP is built as it downloads, so it has no `Content-Length` and can't be resumed with `Range`. A single file supports `Range` requests and may be answered with a `302` redirect to your storage instead.",
            "headers": {
              "Content-Disposition": {
                "description": "`attachment` with the file name.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/zip": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "302": {
            "description": "On storage that supports it, a single file is served from a temporary storage address.",
            "headers": {
              "Location": {
                "description": "A temporary download address.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such file request, or it has no files yet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "request": {
                    "value": {
                      "success": false,
                      "error": "Not Found",
                      "message": "File request not found"
                    }
                  },
                  "empty": {
                    "value": {
                      "success": false,
                      "error": "Not Found",
                      "message": "Nothing to download"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "post": {
        "operationId": "downloadFileRequestSelection",
        "summary": "Download a selection",
        "description": "Downloads selected uploads, files and folders from a request. Send the selection as a form field `items` holding a JSON array, up to 5,000 items, in a body of up to 2 MB. One single-file upload or one file inside an upload comes as itself; anything else as one ZIP.",
        "tags": [
          "File requests"
        ],
        "security": [
          {
            "token": [
              "requests:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file request's ID."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "items"
                ],
                "properties": {
                  "items": {
                    "type": "string",
                    "description": "A JSON array of `ReceivedItemSelection` objects, 1 to 5,000 of them.",
                    "contentMediaType": "application/json",
                    "contentSchema": {
                      "type": "array",
                      "minItems": 1,
                      "maxItems": 5000,
                      "items": {
                        "$ref": "#/components/schemas/ReceivedItemSelection"
                      }
                    }
                  }
                }
              },
              "example": {
                "items": "[{\"file_id\": \"Xy7Kp2Lm\", \"path\": \"July/\"}, {\"file_id\": \"Qw4Rt8Zn\"}]"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The files. One single file comes as itself, and one file inside an upload as that file; anything else comes as a ZIP named after the request, with a folder per sender when several people sent files. A ZIP is built as it downloads, so it has no `Content-Length` and can't be resumed with `Range`. A single file supports `Range` requests and may be answered with a `302` redirect to your storage instead.",
            "headers": {
              "Content-Disposition": {
                "description": "`attachment` with the file name.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/zip": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "302": {
            "description": "On storage that supports it, a single file is served from a temporary storage address.",
            "headers": {
              "Location": {
                "description": "A temporary download address.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          },
          "400": {
            "description": "The selection is missing, empty, not valid JSON or has more than 5,000 items.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Invalid selection"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such file request, or a selected upload, file or folder isn't part of it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "File not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/file-requests/{id}/links": {
      "post": {
        "operationId": "createLinkFromReceivedFiles",
        "summary": "Share received files",
        "description": "Creates a shared link of your own to files a request received. A whole upload is shared as it is stored: the link keeps those files after the request is deleted, until the link expires. Anything else (a file or folder inside an upload, or several items) is copied into a new file first, up to 1 GB and 2,000 files. The link follows your administrator's link expiry; with email protection, each recipient is emailed an invitation.",
        "tags": [
          "File requests"
        ],
        "security": [
          {
            "token": [
              "requests:read",
              "files:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file request's ID."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "items"
                ],
                "properties": {
                  "items": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 5000,
                    "items": {
                      "$ref": "#/components/schemas/ReceivedItemSelection"
                    },
                    "description": "What to share."
                  },
                  "link": {
                    "$ref": "#/components/schemas/ReceivedLinkSettings"
                  }
                }
              },
              "example": {
                "items": [
                  {
                    "file_id": "Xy7Kp2Lm"
                  }
                ],
                "link": {
                  "link_type": "protected",
                  "protection_method": "email",
                  "email_recipients": [
                    {
                      "email": "bob@example.com"
                    }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The link was created.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/ReceivedFileLink"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "message": "Link created",
                  "data": {
                    "file": {
                      "id": "Zt5Np3Ws",
                      "name": "receipts.zip",
                      "size": 4194304,
                      "mime_type": "application/zip",
                      "link_type": "protected",
                      "protection_method": "email",
                      "domain_hostname": "files.example.com",
                      "expires_at": "2026-11-03T10:20:00Z"
                    },
                    "url": "https://files.example.com/p/Zt5Np3Ws",
                    "formatted_text": "https://files.example.com/p/Zt5Np3Ws"
                  }
                }
              }
            }
          },
          "400": {
            "description": "The selection or link settings are invalid, or a copy would exceed 1 GB or 2,000 files.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "selection": {
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Invalid selection"
                    }
                  },
                  "too_big": {
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Links can include up to 1 GB and 2,000 files. To share more, create a link to a whole upload."
                    }
                  },
                  "settings": {
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Password is required"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks one of the permissions, or the user's account is unlicensed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "unlicensed": {
                    "value": {
                      "success": false,
                      "error": "Unlicensed",
                      "message": "Your account is unlicensed. Contact your administrator to restore upload access."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such file request, or a selected upload, file or folder isn't part of it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "File not found"
                }
              }
            }
          },
          "413": {
            "description": "A copy is larger than the domain's upload limit or the storage accepts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Payload Too Large",
                  "message": "Total size exceeds limit (10 GB)"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "507": {
            "description": "Not enough storage space for the copy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Insufficient Storage",
                  "message": "Not enough storage space for this upload"
                }
              }
            }
          }
        }
      }
    },
    "/api/file-requests/{id}/files": {
      "get": {
        "operationId": "listReceivedFiles",
        "summary": "List received files",
        "description": "Lists every file the request received, across uploads and folders, sorted by name, 500 per page. With `q`, returns only files whose name contains it.",
        "tags": [
          "File requests"
        ],
        "security": [
          {
            "token": [
              "requests:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file request's ID."
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "description": "Search text. Matches file names containing it, ignoring case; leave it out to list instead of search."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "description": "How many items to skip. Each page holds up to 500 items."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "responses": {
          "200": {
            "description": "One page of files.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "required": [
                            "items",
                            "total"
                          ],
                          "properties": {
                            "items": {
                              "type": "array",
                              "items": {
                                "$ref": "#/components/schemas/ReceivedFile"
                              }
                            },
                            "total": {
                              "type": "integer",
                              "description": "How many files match in all."
                            }
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "file_id": "Qw4Rt8Zn",
                        "path": "",
                        "name": "invoice-0912.pdf",
                        "size": 1048576,
                        "sender_email": "bob@example.com",
                        "sender_name": "Bob Jensen",
                        "received_at": "2026-10-02T14:15:00Z"
                      },
                      {
                        "file_id": "Xy7Kp2Lm",
                        "path": "July/receipt-0714.pdf",
                        "name": "receipt-0714.pdf",
                        "size": 1398101,
                        "sender_email": "anna@example.com",
                        "received_at": "2026-10-01T16:40:00Z"
                      }
                    ],
                    "total": 2
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such file request, or it belongs to someone else.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "File request not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/file-requests/{id}/files/{file_id}": {
      "get": {
        "operationId": "downloadReceivedUpload",
        "summary": "Download an upload",
        "description": "Downloads one upload as it is stored: the file, or for an upload of several files, its ZIP. Supports `Range` requests for resuming.",
        "tags": [
          "File requests"
        ],
        "security": [
          {
            "token": [
              "requests:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file request's ID."
          },
          {
            "name": "file_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The upload's ID, `file_id` in `uploads` on the file request."
          },
          {
            "name": "preview",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            },
            "description": "Ignored for API tokens, which always get the file as an attachment. In a browser, `1` shows content the browser can display inline."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "responses": {
          "200": {
            "description": "The file. `206` answers a `Range` request.",
            "headers": {
              "Content-Disposition": {
                "description": "`attachment` with the file name.",
                "schema": {
                  "type": "string"
                }
              },
              "Accept-Ranges": {
                "schema": {
                  "type": "string"
                },
                "description": "`bytes`."
              }
            },
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "206": {
            "description": "Part of the file, for a `Range` request.",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "302": {
            "description": "On storage that supports it, a single file is served from a temporary storage address.",
            "headers": {
              "Location": {
                "description": "A temporary download address.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such file request, or the upload isn't part of it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "File not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "delete": {
        "operationId": "deleteReceivedUpload",
        "summary": "Delete an upload",
        "description": "Permanently deletes one upload from a request: a single file, or every file sent together in one upload. A file inside an upload of several files can't be deleted on its own. Files still shared through links made from the upload stay until those links are gone.",
        "tags": [
          "File requests"
        ],
        "security": [
          {
            "token": [
              "requests:delete"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file request's ID."
          },
          {
            "name": "file_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The upload's ID, `file_id` in `uploads` on the file request."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "responses": {
          "200": {
            "description": "The upload was deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such file request, or the upload isn't part of it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "File not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/file-requests/{id}/files/{file_id}/contents": {
      "get": {
        "operationId": "listReceivedFolder",
        "summary": "List files in an upload",
        "description": "Lists one folder of an upload of several files, folders first, then files, sorted by name, 500 per page. With `q`, searches the names of every file and folder below the folder instead. The first page also says how many files the folder holds and their size.",
        "tags": [
          "File requests"
        ],
        "security": [
          {
            "token": [
              "requests:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file request's ID."
          },
          {
            "name": "file_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The upload's ID, `file_id` in `uploads` on the file request."
          },
          {
            "name": "path",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": ""
            },
            "description": "The folder: empty for the top of the upload, else a folder's `path` ending in `/`."
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "description": "Search text. Matches file names containing it, ignoring case; leave it out to list instead of search."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "description": "How many items to skip. Each page holds up to 500 items."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "responses": {
          "200": {
            "description": "One page of the folder.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "required": [
                            "items",
                            "total"
                          ],
                          "properties": {
                            "items": {
                              "type": "array",
                              "items": {
                                "$ref": "#/components/schemas/ReceivedFolderItem"
                              }
                            },
                            "total": {
                              "type": "integer",
                              "description": "How many items match in all."
                            },
                            "file_count": {
                              "type": "integer",
                              "description": "First page only: how many files are under the folder."
                            },
                            "size": {
                              "type": "integer",
                              "format": "int64",
                              "description": "First page only: their total size in bytes."
                            }
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "name": "July",
                        "path": "July/",
                        "is_dir": true,
                        "file_count": 2,
                        "size": 2796202
                      },
                      {
                        "name": "summary.xlsx",
                        "path": "summary.xlsx",
                        "is_dir": false,
                        "file_count": 1,
                        "size": 1398102
                      }
                    ],
                    "total": 2,
                    "file_count": 3,
                    "size": 4194304
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such file request, the upload isn't part of it, or it is a single file.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "File not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/file-requests/{id}/files/{file_id}/entry": {
      "get": {
        "operationId": "downloadReceivedEntry",
        "summary": "Download a file or folder from an upload",
        "description": "Downloads one file, or one folder as a ZIP, from inside an upload of several files. Neither supports `Range` requests.",
        "tags": [
          "File requests"
        ],
        "security": [
          {
            "token": [
              "requests:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The file request's ID."
          },
          {
            "name": "file_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The upload's ID, `file_id` in `uploads` on the file request."
          },
          {
            "name": "path",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "A file's `path` inside the upload, or a folder's ending in `/`, as the contents endpoint lists them."
          },
          {
            "name": "preview",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            },
            "description": "Ignored for API tokens, which always get the file as an attachment. In a browser, `1` shows content the browser can display inline."
          },
          {
            "$ref": "#/components/parameters/ActAs"
          }
        ],
        "responses": {
          "200": {
            "description": "The file, with its `Content-Length`, or the folder as a ZIP built as it downloads, without one.",
            "headers": {
              "Content-Disposition": {
                "description": "`attachment` with the file or folder name.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/zip": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "`path` is missing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "path is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No such file request, the upload isn't part of it, or the path isn't in it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "File not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/users": {
      "get": {
        "operationId": "listUsers",
        "summary": "List users",
        "description": "Lists users, newest first, admins included. Service accounts are not included. Returns up to `limit` users; for the next page, pass the `created_at` and `id` of the last user you received as `cursor_ts` and `cursor_id`. Under an API token, only users with one of the service account's domains are listed.",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "token": [
              "users:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 200
            },
            "description": "How many users to return. A value outside 1 to 200 is ignored and the default used."
          },
          {
            "name": "cursor_ts",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "`created_at` of the last user on the previous page. Applies only together with `cursor_id`; an unreadable value is ignored and the first page returned."
          },
          {
            "name": "cursor_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "`id` of the last user on the previous page. Applies only together with `cursor_ts`."
          }
        ],
        "responses": {
          "200": {
            "description": "The users.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/AdminUser"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "3f2b8c1e-6a4d-4e2f-9b7a-1c5d8e9f0a12",
                      "displayname": "Anna Berg",
                      "email": "anna@example.com",
                      "user_status": "active",
                      "is_admin": false,
                      "domain_ids": [
                        "b1c2d3e4-5f60-4a7b-8c9d-0e1f2a3b4c5d"
                      ],
                      "auth_provider": "local",
                      "is_break_glass": false,
                      "created_at": "2026-09-14T08:32:11.402Z",
                      "is_scim_connection": false,
                      "is_sso_orphan": false,
                      "avatar_url": "https://files.example.com/avatars/4c1d9a0e7b2f48a6b3e5d7c9f1a2b3c4"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "post": {
        "operationId": "createUser",
        "summary": "Create a user",
        "description": "Creates an active user who signs in with the password you set. `domain_ids` puts the user on those domains' access lists and `group_ids` adds them to Local groups; without either they can't use the app until you put them on a domain's access list with `PUT /api/admin/domains/{id}/access/users/{userID}` or add them to a group that has access. Under an API token, `domain_ids` is required and may list only the service account's domains: a domain outside them is refused with 403. `group_ids` under an API token needs the `groups:write` permission too. Takes a seat on the license. API tokens can't create admins: `is_admin: true` is refused with 403. A pending admin invitation for the same email is refused with 403 too, since the new user would replace it.",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "token": [
              "users:write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateUserRequest"
              },
              "example": {
                "displayname": "Bob Lund",
                "email": "bob@example.com",
                "password": "Correct-Horse-42"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The user was created.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/CreatedUser"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "8d4e2a7b-1f3c-4b9d-a6e5-2c7f9b0d3e45"
                  },
                  "message": "User created"
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "json": {
                    "summary": "The body isn't valid JSON",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Invalid JSON"
                    }
                  },
                  "missing": {
                    "summary": "A field is empty",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "All fields required"
                    }
                  },
                  "policy": {
                    "summary": "The password doesn't meet the password policy; `message` is the policy's guidance",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Use at least 12 characters, with upper and lower case letters and a number."
                    }
                  },
                  "group": {
                    "summary": "A group in `group_ids` doesn't exist or isn't a Local group",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "One of the groups in group_ids doesn't exist or is managed in your identity provider."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, tried to create an admin or replace a pending admin invitation, the license has no seat left, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "groups_scope_missing": {
                    "summary": "`group_ids` is set and the token lacks `groups:write`",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission to add users to groups."
                    }
                  },
                  "admin_target": {
                    "summary": "The user is an admin",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "API tokens can't create or manage admins."
                    }
                  },
                  "license_limit": {
                    "summary": "No seat left on the license",
                    "value": {
                      "success": false,
                      "error": "License Limit Reached",
                      "message": "User limit reached (25/25, including pending invites). Revoke unused invites or upgrade your license to add more users."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "A user with this email already exists.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Conflict",
                  "message": "A user with this email already exists. Enter a different email."
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/users/{id}": {
      "delete": {
        "operationId": "deleteUser",
        "summary": "Delete a user",
        "description": "Deletes the user and everything they own: their shared links, their file requests and the files received through them are permanently deleted. To keep their files, transfer them first with `POST /api/admin/users/{id}/transfer`. Under an API token, admins can't be managed: the request is refused with 403. Service accounts are not users here and answer 404. Under an API token, the user must have one of the service account's domains; anyone else answers 404.",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "token": [
              "users:delete"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The user's ID."
          }
        ],
        "responses": {
          "200": {
            "description": "The user was deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true,
                  "message": "User deleted"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, the user is an admin, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "admin_target": {
                    "summary": "The user is an admin",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "API tokens can't create or manage admins."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such user. Service accounts are not users here and also answer 404.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "User not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/users/{id}/transfer": {
      "post": {
        "operationId": "transferUserOwnership",
        "summary": "Transfer a user's files and requests",
        "description": "Moves all of the user's files and file requests, with the files received through them, to another active user. Their shared links keep working. Files people are still sending to those requests carry on; the user's own unfinished uploads are canceled. Under an API token, admins can't be managed: the request is refused with 403. Service accounts are not users here and answer 404. Under an API token, the user must have one of the service account's domains; anyone else answers 404.",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "token": [
              "users:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The user's ID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransferOwnershipRequest"
              },
              "example": {
                "to_user_id": "8d4e2a7b-1f3c-4b9d-a6e5-2c7f9b0d3e45"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The files and requests were transferred.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true,
                  "message": "Files and requests transferred"
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "json": {
                    "summary": "The body isn't valid JSON",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Invalid JSON"
                    }
                  },
                  "target": {
                    "summary": "The receiving user isn't another active user",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Choose another active user to receive the files and requests."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, the user is an admin, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "admin_target": {
                    "summary": "The user is an admin",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "API tokens can't create or manage admins."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such user. Service accounts are not users here and also answer 404.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "User not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/users/{id}/delete-impact": {
      "get": {
        "operationId": "getUserDeleteImpact",
        "summary": "Count what deleting a user removes",
        "description": "Counts the shared links, file requests and received files that deleting the user would permanently delete. Under an API token, admins can't be managed: the request is refused with 403. Service accounts are not users here and answer 404. Under an API token, the user must have one of the service account's domains; anyone else answers 404.",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "token": [
              "users:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The user's ID."
          }
        ],
        "responses": {
          "200": {
            "description": "The counts.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/UserDeleteImpact"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "shared_links": 12,
                    "file_requests": 3,
                    "received_files": 41
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, the user is an admin, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "admin_target": {
                    "summary": "The user is an admin",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "API tokens can't create or manage admins."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such user. Service accounts are not users here and also answer 404.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "User not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/users/{id}/status": {
      "put": {
        "operationId": "setUserStatus",
        "summary": "Activate or deactivate a user",
        "description": "Deactivating signs the user out everywhere, the desktop app included, and revokes their personal tokens; their files and requests stay. Activating takes a seat on the license. Users managed by SCIM, or whose email domain is no longer on their single sign-on connection, can't be activated here. Asking for the status the user already has changes nothing. Under an API token, admins can't be managed: the request is refused with 403. Service accounts are not users here and answer 404. Under an API token, the user must have one of the service account's domains; anyone else answers 404.",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "token": [
              "users:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The user's ID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetUserStatusRequest"
              },
              "example": {
                "user_status": "inactive"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The status was updated, or already was the one asked for (`message` is then `User is already active` or `User is already inactive`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true,
                  "message": "User status updated to inactive"
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "json": {
                    "summary": "The body isn't valid JSON",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Invalid JSON"
                    }
                  },
                  "status": {
                    "summary": "Unknown status",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "User status must be 'active' or 'inactive'"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, the user is an admin, the license has no seat left, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "admin_target": {
                    "summary": "The user is an admin",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "API tokens can't create or manage admins."
                    }
                  },
                  "license_limit": {
                    "summary": "No seat left on the license",
                    "value": {
                      "success": false,
                      "error": "License Limit Reached",
                      "message": "User limit reached (25/25, including pending invites). Revoke unused invites or upgrade your license to add more users."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such user. Service accounts are not users here and also answer 404.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "User not found"
                }
              }
            }
          },
          "409": {
            "description": "The user signs in with single sign-on and can't be activated here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scim": {
                    "summary": "Managed by SCIM",
                    "value": {
                      "success": false,
                      "error": "SSOManaged",
                      "message": "This user is managed by SCIM. Re-enable them in your identity provider, or convert to a local account."
                    }
                  },
                  "orphan": {
                    "summary": "Email domain no longer on the connection",
                    "value": {
                      "success": false,
                      "error": "SSOOrphan",
                      "message": "This user's email domain is no longer on the SSO connection. Re-add the domain to the connection, or convert to a local account."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/users/{id}/send-password-reset": {
      "post": {
        "operationId": "sendUserPasswordReset",
        "summary": "Email a user a password reset link",
        "description": "Emails the user a link to set a new password. The link expires after 24 hours and is not returned to you. Only for active users who sign in with a password. Under an API token, admins can't be managed: the request is refused with 403. Service accounts are not users here and answer 404. Under an API token, the user must have one of the service account's domains; anyone else answers 404.",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "token": [
              "users:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The user's ID."
          }
        ],
        "responses": {
          "200": {
            "description": "The email was sent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true,
                  "message": "Password reset link sent"
                }
              }
            }
          },
          "400": {
            "description": "The user can't get a reset link.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "inactive": {
                    "summary": "The user is inactive",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Cannot send reset link to an inactive user"
                    }
                  },
                  "sso": {
                    "summary": "The user signs in with single sign-on",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Password reset is only available for local accounts"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, the user is an admin, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "admin_target": {
                    "summary": "The user is an admin",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "API tokens can't create or manage admins."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such user. Service accounts are not users here and also answer 404.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "User not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "description": "The email couldn't be sent. Check the email settings.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Error",
                  "message": "Failed to send password reset link"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/users/{id}/avatar": {
      "delete": {
        "operationId": "deleteUserAvatar",
        "summary": "Remove a user's profile picture",
        "description": "Removes the user's profile picture. Also succeeds when the user has none. Under an API token, admins can't be managed: the request is refused with 403. Service accounts are not users here and answer 404. Under an API token, the user must have one of the service account's domains; anyone else answers 404.",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "token": [
              "users:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The user's ID."
          }
        ],
        "responses": {
          "200": {
            "description": "The picture was removed, or there was none.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true,
                  "message": "Profile picture removed"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, the user is an admin, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "admin_target": {
                    "summary": "The user is an admin",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "API tokens can't create or manage admins."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such user. Service accounts are not users here and also answer 404.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "User not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/users/{id}/access": {
      "get": {
        "operationId": "getUserAccess",
        "summary": "Get a user's access",
        "description": "Lists the groups the user is in, and every domain they have access to with how they got it: their own place on the domain's access list, a group, or both. Service accounts are not users here and answer 404. Under an API token, the user must have one of the service account's domains; anyone else answers 404. Admins can't be managed under an API token: the request is refused with 403.",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "token": [
              "users:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The user's ID."
          }
        ],
        "responses": {
          "200": {
            "description": "The user's groups and domains.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/UserAccess"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "groups": [
                      {
                        "id": "everyone",
                        "kind": "everyone",
                        "name": "Everyone",
                        "source": "everyone"
                      },
                      {
                        "id": "7a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
                        "kind": "local",
                        "name": "Legal",
                        "source": "added"
                      }
                    ],
                    "domains": [
                      {
                        "domain_id": "b1c2d3e4-5f60-4a7b-8c9d-0e1f2a3b4c5d",
                        "hostname": "files.example.com",
                        "is_active": true,
                        "routes": [
                          {},
                          {
                            "group_id": "7a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
                            "group_name": "Legal"
                          }
                        ]
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, the user is an admin, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "admin_target": {
                    "summary": "The user is an admin",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "API tokens can't create or manage admins."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such user. Service accounts are not users here and also answer 404.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "User not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/invites": {
      "post": {
        "operationId": "createInvite",
        "summary": "Invite a user",
        "description": "Emails the person an invitation to create their account. The link expires after 3 days. A pending invitation takes a seat on the license. A new invitation to the same email closes the earlier one. API tokens can't invite admins: `is_admin: true` is refused with 403. A pending admin invitation for the same email is refused with 403 too, since a new invitation would replace it. Under an API token, `domain_ids` is required and may list only the service account's domains, and the new invitation closes earlier ones only where they give one of those domains. `group_ids` adds the person to Local groups when they accept; under an API token it needs the `groups:write` permission too.",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "token": [
              "users:write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateInviteRequest"
              },
              "example": {
                "email": "bob@example.com",
                "domain_ids": [
                  "b1c2d3e4-5f60-4a7b-8c9d-0e1f2a3b4c5d"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The invitation was sent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true,
                  "message": "Invite sent"
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "json": {
                    "summary": "The body isn't valid JSON",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Invalid JSON"
                    }
                  },
                  "email_missing": {
                    "summary": "No email",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Email is required"
                    }
                  },
                  "email_invalid": {
                    "summary": "Not an email address",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Email is invalid"
                    }
                  },
                  "exists": {
                    "summary": "The email belongs to a user",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "User already exists"
                    }
                  },
                  "group": {
                    "summary": "A group in `group_ids` doesn't exist or isn't a Local group",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "One of the groups in group_ids doesn't exist or is managed in your identity provider."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, tried to invite an admin or replace a pending admin invitation, the license has no seat left, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "groups_scope_missing": {
                    "summary": "`group_ids` is set and the token lacks `groups:write`",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission to add users to groups."
                    }
                  },
                  "admin_target": {
                    "summary": "The user is an admin",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "API tokens can't create or manage admins."
                    }
                  },
                  "license_limit": {
                    "summary": "No seat left on the license",
                    "value": {
                      "success": false,
                      "error": "License Limit Reached",
                      "message": "User limit reached (25/25, including pending invites). Revoke unused invites or upgrade your license to add more users."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "description": "The invitation email couldn't be sent. `ref` points your admin to the details in the system logs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "INVITE_SEND",
                  "message": "Failed to send the invitation email",
                  "ref": "REF-a3f8b2c1"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "listInvites",
        "summary": "List pending invitations",
        "description": "Lists invitations not yet accepted or revoked, newest first, at most 500. Expired invitations stay listed for 7 days after they expire, so you can resend them. Under an API token, only invitations that give one of the service account's domains are listed.",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "token": [
              "users:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "The invitations.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Invite"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b",
                      "email": "bob@example.com",
                      "domain_ids": [
                        "b1c2d3e4-5f60-4a7b-8c9d-0e1f2a3b4c5d"
                      ],
                      "group_ids": [],
                      "expires_at": "2026-10-07T09:15:00Z",
                      "created_at": "2026-10-04T09:15:00Z",
                      "expired": false
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/invites/{id}/revoke": {
      "post": {
        "operationId": "revokeInvite",
        "summary": "Revoke an invitation",
        "description": "The invitation link stops working and its seat on the license is freed. API tokens can't revoke an admin's invitation: the request is refused with 403. Under an API token, the invitation must give one of the service account's domains; any other answers 404.",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "token": [
              "users:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The invitation's ID."
          }
        ],
        "responses": {
          "200": {
            "description": "The invitation was revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true,
                  "message": "Invite revoked"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, the invitation is an admin's, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such invitation, or it was already accepted or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "Invite not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/invites/{id}/resend": {
      "post": {
        "operationId": "resendInvite",
        "summary": "Resend an invitation",
        "description": "Emails a new invitation link that expires 3 days from now; the previous link stops working. Works for expired invitations too, which then take a seat on the license again. If the email can't be sent, the previous link keeps working. API tokens can't resend an admin's invitation: the request is refused with 403. Under an API token, the invitation must give one of the service account's domains; any other answers 404.",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "token": [
              "users:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The invitation's ID."
          }
        ],
        "responses": {
          "200": {
            "description": "The invitation was resent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true,
                  "message": "Invite resent"
                }
              }
            }
          },
          "400": {
            "description": "The invitation can't be resent: it was used or revoked, or the person already has an account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "closed": {
                    "summary": "Already accepted or revoked",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Invite is no longer valid"
                    }
                  },
                  "exists": {
                    "summary": "The email now belongs to a user",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "User already exists"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, the invitation is an admin's, the license has no seat left for an expired invitation, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "license_limit": {
                    "summary": "No seat left on the license",
                    "value": {
                      "success": false,
                      "error": "License Limit Reached",
                      "message": "User limit reached (25/25, including pending invites). Revoke unused invites or upgrade your license to add more users."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such invitation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "Invite not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "description": "The invitation email couldn't be sent. `ref` points your admin to the details in the system logs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "INVITE_SEND",
                  "message": "Failed to send the invitation email",
                  "ref": "REF-a3f8b2c1"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/domains/{id}/access/users/{userID}": {
      "put": {
        "operationId": "addDomainAccessUser",
        "summary": "Give a user access to a domain",
        "description": "Puts the user on the domain's access list. Does nothing if they are already on it. Under an API token, the domain must be one of the service account's domains (403 otherwise), and the user must have one of them too (404 otherwise). Service accounts are not users here and answer 404. Admins can't be managed under an API token: the request is refused with 403.",
        "tags": [
          "Groups"
        ],
        "security": [
          {
            "token": [
              "users:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The domain's ID, from `GET /api/admin/domains`."
          },
          {
            "name": "userID",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The user's ID."
          }
        ],
        "responses": {
          "200": {
            "description": "The user is on the access list.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true,
                  "message": "Access updated"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, the domain isn't one of the service account's, the user is an admin, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "own_domains": {
                    "summary": "The domain isn't one of the service account's domains",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "This service account can only change access to its own domains."
                    }
                  },
                  "admin_target": {
                    "summary": "The user is an admin",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "API tokens can't create or manage admins."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such domain or user, or for a removal, the user isn't on the access list themselves. Service accounts are not users here and also answer 404.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "user": {
                    "summary": "No such user",
                    "value": {
                      "success": false,
                      "error": "Not Found",
                      "message": "User not found"
                    }
                  },
                  "row": {
                    "summary": "No such domain, or no such row",
                    "value": {
                      "success": false,
                      "error": "Not Found",
                      "message": "Not found"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "delete": {
        "operationId": "removeDomainAccessUser",
        "summary": "Remove a user from a domain's access list",
        "description": "Takes the user's own place off the domain's access list. Access they have through a group stays. Under an API token, the domain must be one of the service account's domains (403 otherwise), and the user must have one of them too (404 otherwise). Service accounts are not users here and answer 404. Admins can't be managed under an API token: the request is refused with 403.",
        "tags": [
          "Groups"
        ],
        "security": [
          {
            "token": [
              "users:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The domain's ID, from `GET /api/admin/domains`."
          },
          {
            "name": "userID",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The user's ID."
          }
        ],
        "responses": {
          "200": {
            "description": "The user is off the access list.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true,
                  "message": "Access updated"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, the domain isn't one of the service account's, the user is an admin, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "own_domains": {
                    "summary": "The domain isn't one of the service account's domains",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "This service account can only change access to its own domains."
                    }
                  },
                  "admin_target": {
                    "summary": "The user is an admin",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "API tokens can't create or manage admins."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such domain or user, or for a removal, the user isn't on the access list themselves. Service accounts are not users here and also answer 404.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "user": {
                    "summary": "No such user",
                    "value": {
                      "success": false,
                      "error": "Not Found",
                      "message": "User not found"
                    }
                  },
                  "row": {
                    "summary": "No such domain, or no such row",
                    "value": {
                      "success": false,
                      "error": "Not Found",
                      "message": "Not found"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/groups": {
      "get": {
        "operationId": "listGroups",
        "summary": "List groups",
        "description": "Lists every group: Everyone first, then Local and SCIM groups by name.",
        "tags": [
          "Groups"
        ],
        "security": [
          {
            "token": [
              "groups:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "The groups.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Group"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "everyone",
                      "kind": "everyone",
                      "name": "Everyone",
                      "email_domains": [],
                      "member_count": 24,
                      "created_at": "2026-09-01T10:00:00Z",
                      "updated_at": "2026-09-01T10:00:00Z"
                    },
                    {
                      "id": "7a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
                      "kind": "local",
                      "name": "Legal",
                      "email_domains": [],
                      "member_count": 2,
                      "created_at": "2026-09-14T08:32:11.402Z",
                      "updated_at": "2026-09-14T08:32:11.402Z"
                    },
                    {
                      "id": "2e3f4a5b-6c7d-4e8f-9a0b-1c2d3e4f5a6b",
                      "kind": "scim",
                      "name": "Sales",
                      "email_domains": [],
                      "member_count": 9,
                      "created_at": "2026-09-14T08:32:11.402Z",
                      "updated_at": "2026-10-02T12:04:51Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "post": {
        "operationId": "createGroup",
        "summary": "Create a group",
        "description": "Creates a Local group. With `email_domains`, users with an email at those domains are members without being added, now and when they join later.",
        "tags": [
          "Groups"
        ],
        "security": [
          {
            "token": [
              "groups:write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GroupRequest"
              },
              "example": {
                "name": "Legal",
                "email_domains": [
                  "legal.example.com"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The group was created.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/Group"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "7a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
                    "kind": "local",
                    "name": "Legal",
                    "email_domains": [
                      "legal.example.com"
                    ],
                    "member_count": 0,
                    "created_at": "2026-09-14T08:32:11.402Z",
                    "updated_at": "2026-09-14T08:32:11.402Z"
                  },
                  "message": "Group created"
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "json": {
                    "summary": "The body isn't valid JSON",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Invalid JSON"
                    }
                  },
                  "name": {
                    "summary": "The name is empty or longer than 100 characters",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Enter a group name of up to 100 characters."
                    }
                  },
                  "email_domains": {
                    "summary": "An email domain isn't valid",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Enter email domains like example.com."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Another Local group or Everyone has this name, ignoring case.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Conflict",
                  "message": "A group with this name already exists."
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/groups/{id}": {
      "get": {
        "operationId": "getGroup",
        "summary": "Get a group",
        "description": "Returns the group with its members, the people its email rule matches who are excluded, and the domains it gives access to. Members are left out for Everyone, which is every user except service accounts. Under an API token, only members on the service account's domains are listed.",
        "tags": [
          "Groups"
        ],
        "security": [
          {
            "token": [
              "groups:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The group's ID."
          }
        ],
        "responses": {
          "200": {
            "description": "The group.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/GroupDetail"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "7a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
                    "kind": "local",
                    "name": "Legal",
                    "email_domains": [],
                    "member_count": 2,
                    "created_at": "2026-09-14T08:32:11.402Z",
                    "updated_at": "2026-09-14T08:32:11.402Z",
                    "members": [
                      {
                        "user_id": "3f2b8c1e-6a4d-4e2f-9b7a-1c5d8e9f0a12",
                        "email": "anna@example.com",
                        "displayname": "Anna Berg",
                        "source": "added",
                        "avatar_url": ""
                      },
                      {
                        "user_id": "8d4e2a7b-1f3c-4b9d-a6e5-2c7f9b0d3e45",
                        "email": "bob@example.com",
                        "displayname": "Bob Lund",
                        "source": "added",
                        "avatar_url": ""
                      }
                    ],
                    "access": [
                      {
                        "domain_id": "b1c2d3e4-5f60-4a7b-8c9d-0e1f2a3b4c5d",
                        "hostname": "files.example.com",
                        "sole_access_count": 1
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such group.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "Group not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "put": {
        "operationId": "updateGroup",
        "summary": "Update a group",
        "description": "Renames a Local group and sets its email rule. Leaving out `email_domains` removes the rule. Exclusions stay when the rule changes. SCIM groups and Everyone can't be changed: they answer 409.",
        "tags": [
          "Groups"
        ],
        "security": [
          {
            "token": [
              "groups:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The group's ID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GroupRequest"
              },
              "example": {
                "name": "Legal",
                "email_domains": [
                  "legal.example.com"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The group was updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true,
                  "message": "Group updated"
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "json": {
                    "summary": "The body isn't valid JSON",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Invalid JSON"
                    }
                  },
                  "name": {
                    "summary": "The name is empty or longer than 100 characters",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Enter a group name of up to 100 characters."
                    }
                  },
                  "email_domains": {
                    "summary": "An email domain isn't valid",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Enter email domains like example.com."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such group.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "Group not found"
                }
              }
            }
          },
          "409": {
            "description": "The group is a SCIM group or Everyone, or another Local group or Everyone has this name, ignoring case.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "name_taken": {
                    "summary": "The name is taken",
                    "value": {
                      "success": false,
                      "error": "Conflict",
                      "message": "A group with this name already exists."
                    }
                  },
                  "scim": {
                    "summary": "A SCIM group",
                    "value": {
                      "success": false,
                      "error": "Conflict",
                      "message": "This group is managed in your identity provider."
                    }
                  },
                  "everyone": {
                    "summary": "Everyone",
                    "value": {
                      "success": false,
                      "error": "Conflict",
                      "message": "Everyone always includes every user."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "delete": {
        "operationId": "deleteGroup",
        "summary": "Delete a group",
        "description": "Deletes a Local group and takes it off every domain's access list. Its members lose access they have only through this group. SCIM groups and Everyone can't be deleted: they answer 409. API tokens can't delete a group that gives access to domains: the request is refused with 403.",
        "tags": [
          "Groups"
        ],
        "security": [
          {
            "token": [
              "groups:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The group's ID."
          }
        ],
        "responses": {
          "200": {
            "description": "The group was deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true,
                  "message": "Group deleted"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such group.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "Group not found"
                }
              }
            }
          },
          "409": {
            "description": "The group is a SCIM group or Everyone, which can't be changed here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scim": {
                    "summary": "A SCIM group",
                    "value": {
                      "success": false,
                      "error": "Conflict",
                      "message": "This group is managed in your identity provider."
                    }
                  },
                  "everyone": {
                    "summary": "Everyone",
                    "value": {
                      "success": false,
                      "error": "Conflict",
                      "message": "Everyone always includes every user."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/groups/{id}/members": {
      "post": {
        "operationId": "addGroupMembers",
        "summary": "Add members to a group",
        "description": "Adds users to a Local group. Adding someone who was excluded includes them again. Users already in the group and service accounts are skipped. Under an API token, only users with one of the service account's domains who aren't admins can be changed; anyone else is skipped. SCIM groups and Everyone answer 409.",
        "tags": [
          "Groups"
        ],
        "security": [
          {
            "token": [
              "groups:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The group's ID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GroupMembersRequest"
              },
              "example": {
                "user_ids": [
                  "3f2b8c1e-6a4d-4e2f-9b7a-1c5d8e9f0a12",
                  "8d4e2a7b-1f3c-4b9d-a6e5-2c7f9b0d3e45"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The members were added.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true,
                  "message": "Group members updated"
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "json": {
                    "summary": "The body isn't valid JSON",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Invalid JSON"
                    }
                  },
                  "empty": {
                    "summary": "`user_ids` is empty",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Choose at least one user."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such group.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "Group not found"
                }
              }
            }
          },
          "409": {
            "description": "The group is a SCIM group or Everyone, which can't be changed here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scim": {
                    "summary": "A SCIM group",
                    "value": {
                      "success": false,
                      "error": "Conflict",
                      "message": "This group is managed in your identity provider."
                    }
                  },
                  "everyone": {
                    "summary": "Everyone",
                    "value": {
                      "success": false,
                      "error": "Conflict",
                      "message": "Everyone always includes every user."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/groups/{id}/members/{userID}": {
      "delete": {
        "operationId": "removeGroupMember",
        "summary": "Remove a member from a group",
        "description": "Removes a user who was added to a Local group. If the group's email rule matches them, they stay in through the rule; to take them out, exclude them. Under an API token, only users with one of the service account's domains who aren't admins can be changed; anyone else answers 404. SCIM groups and Everyone answer 409.",
        "tags": [
          "Groups"
        ],
        "security": [
          {
            "token": [
              "groups:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The group's ID."
          },
          {
            "name": "userID",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The user's ID."
          }
        ],
        "responses": {
          "200": {
            "description": "The member was removed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true,
                  "message": "Group members updated"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such group, or the user isn't in it this way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "group": {
                    "summary": "No such group",
                    "value": {
                      "success": false,
                      "error": "Not Found",
                      "message": "Group not found"
                    }
                  },
                  "user": {
                    "summary": "The user isn't in the group this way",
                    "value": {
                      "success": false,
                      "error": "Not Found",
                      "message": "User not found in this group"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "The group is a SCIM group or Everyone, which can't be changed here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scim": {
                    "summary": "A SCIM group",
                    "value": {
                      "success": false,
                      "error": "Conflict",
                      "message": "This group is managed in your identity provider."
                    }
                  },
                  "everyone": {
                    "summary": "Everyone",
                    "value": {
                      "success": false,
                      "error": "Conflict",
                      "message": "Everyone always includes every user."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/groups/{id}/exclusions/{userID}": {
      "put": {
        "operationId": "excludeGroupMember",
        "summary": "Exclude a user from a group",
        "description": "Keeps a user the Local group's email rule matches out of the group. Only users the rule matches can be excluded. Under an API token, only users with one of the service account's domains who aren't admins can be changed; anyone else answers 404. SCIM groups and Everyone answer 409.",
        "tags": [
          "Groups"
        ],
        "security": [
          {
            "token": [
              "groups:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The group's ID."
          },
          {
            "name": "userID",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The user's ID."
          }
        ],
        "responses": {
          "200": {
            "description": "The user was excluded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true,
                  "message": "Group members updated"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such group, or the user isn't in it this way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "group": {
                    "summary": "No such group",
                    "value": {
                      "success": false,
                      "error": "Not Found",
                      "message": "Group not found"
                    }
                  },
                  "user": {
                    "summary": "The user isn't in the group this way",
                    "value": {
                      "success": false,
                      "error": "Not Found",
                      "message": "User not found in this group"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "The group is a SCIM group or Everyone, which can't be changed here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scim": {
                    "summary": "A SCIM group",
                    "value": {
                      "success": false,
                      "error": "Conflict",
                      "message": "This group is managed in your identity provider."
                    }
                  },
                  "everyone": {
                    "summary": "Everyone",
                    "value": {
                      "success": false,
                      "error": "Conflict",
                      "message": "Everyone always includes every user."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "delete": {
        "operationId": "includeGroupMember",
        "summary": "Include an excluded user again",
        "description": "Removes the exclusion, so the Local group's email rule makes the user a member again. Under an API token, only users with one of the service account's domains who aren't admins can be changed; anyone else answers 404. SCIM groups and Everyone answer 409.",
        "tags": [
          "Groups"
        ],
        "security": [
          {
            "token": [
              "groups:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The group's ID."
          },
          {
            "name": "userID",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The user's ID."
          }
        ],
        "responses": {
          "200": {
            "description": "The user was included again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true,
                  "message": "Group members updated"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such group, or the user isn't in it this way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "group": {
                    "summary": "No such group",
                    "value": {
                      "success": false,
                      "error": "Not Found",
                      "message": "Group not found"
                    }
                  },
                  "user": {
                    "summary": "The user isn't in the group this way",
                    "value": {
                      "success": false,
                      "error": "Not Found",
                      "message": "User not found in this group"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "The group is a SCIM group or Everyone, which can't be changed here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scim": {
                    "summary": "A SCIM group",
                    "value": {
                      "success": false,
                      "error": "Conflict",
                      "message": "This group is managed in your identity provider."
                    }
                  },
                  "everyone": {
                    "summary": "Everyone",
                    "value": {
                      "success": false,
                      "error": "Conflict",
                      "message": "Everyone always includes every user."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/clients": {
      "get": {
        "operationId": "listClientDevices",
        "summary": "List desktop app sign-ins",
        "description": "Lists every computer signed in to the desktop app, for all users (under an API token, those of users with one of the service account's domains), most recently signed in first, at most 1000.",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "token": [
              "users:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "The signed-in computers.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/AdminClientDevice"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "9a8b7c6d-5e4f-4a3b-9c2d-1e0f9a8b7c6d",
                      "user_id": "3f2b8c1e-6a4d-4e2f-9b7a-1c5d8e9f0a12",
                      "user_email": "anna@example.com",
                      "device_name": "ANNA-LAPTOP",
                      "platform": "windows",
                      "os_version": "Windows 11 23H2",
                      "app_version": "1.4.0",
                      "first_seen_at": "2026-08-02T07:41:09Z",
                      "last_seen_at": "2026-10-03T13:05:22Z",
                      "last_used_at": "2026-10-04T08:12:47Z",
                      "last_ip": "203.0.113.24"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/clients/{id}": {
      "delete": {
        "operationId": "revokeClientDevice",
        "summary": "Sign out a desktop app",
        "description": "Signs the desktop app out on that computer; it has to sign in again before it can be used. Under an API token, an admin's computers can't be signed out: the request is refused with 403. Under an API token, the computer's user must have one of the service account's domains; any other answers 404.",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "token": [
              "users:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The device's ID, from `GET /api/admin/clients`."
          }
        ],
        "responses": {
          "200": {
            "description": "The computer was signed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                },
                "example": {
                  "success": true,
                  "message": "Device revoked"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, the computer belongs to an admin, or the admin network allowlist refuses the caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope_missing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "admin_target": {
                    "summary": "The user is an admin",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "API tokens can't create or manage admins."
                    }
                  },
                  "network": {
                    "summary": "The admin network allowlist refuses the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such computer, or it's already signed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "Device not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/smtp-configs": {
      "get": {
        "operationId": "listSmtpConfigs",
        "summary": "List email setups",
        "description": "Lists every email sending setup: SMTP servers and Microsoft 365 app registrations. Passwords and client secrets are never returned.",
        "tags": [
          "Settings"
        ],
        "security": [
          {
            "token": [
              "settings:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/SmtpConfig"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "3f1c2a9e-6b7d-4e21-9c0a-5d8e7f6a1b23",
                      "name": "Company mail",
                      "description": "Main relay",
                      "is_default": true,
                      "is_active": true,
                      "provider": "smtp",
                      "host": "smtp.example.com",
                      "port": 587,
                      "encryption": "starttls",
                      "username": "dew@example.com",
                      "password_set": true,
                      "from_email": "files@example.com",
                      "from_name": "Example Files",
                      "created_at": "2026-09-14T08:12:00Z",
                      "updated_at": "2026-09-20T10:03:41Z",
                      "ms_client_secret_set": false
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request sent a `Dew-Act-As` header. Admin actions can't act as a user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Dew-Act-As can't be used for admin actions."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or admin access isn't allowed from the caller's network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "summary": "Missing permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "Network not allowed",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/smtp-configs/{id}": {
      "get": {
        "operationId": "getSmtpConfig",
        "summary": "Get an email setup",
        "description": "Returns one email sending setup. Passwords and client secrets are never returned.",
        "tags": [
          "Settings"
        ],
        "security": [
          {
            "token": [
              "settings:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Email setup ID."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/SmtpConfig"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "3f1c2a9e-6b7d-4e21-9c0a-5d8e7f6a1b23",
                    "name": "Company mail",
                    "description": "Main relay",
                    "is_default": true,
                    "is_active": true,
                    "provider": "smtp",
                    "host": "smtp.example.com",
                    "port": 587,
                    "encryption": "starttls",
                    "username": "dew@example.com",
                    "password_set": true,
                    "from_email": "files@example.com",
                    "from_name": "Example Files",
                    "created_at": "2026-09-14T08:12:00Z",
                    "updated_at": "2026-09-20T10:03:41Z",
                    "ms_client_secret_set": false
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request sent a `Dew-Act-As` header. Admin actions can't act as a user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Dew-Act-As can't be used for admin actions."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or admin access isn't allowed from the caller's network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "summary": "Missing permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "Network not allowed",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such item.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "SMTP configuration not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/sms-configs": {
      "get": {
        "operationId": "listSmsConfigs",
        "summary": "List SMS setups",
        "description": "Lists every text message provider setup. API keys are never returned. A Twilio setup that is in use but has no sender has `needs_sender` set.",
        "tags": [
          "Settings"
        ],
        "security": [
          {
            "token": [
              "settings:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/SmsConfig"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "8a2d4f60-1c3b-4e5a-9f7d-2b6c8e0a4d19",
                      "name": "Twilio",
                      "is_default": true,
                      "is_active": true,
                      "provider_type": "twilio",
                      "api_key_set": true,
                      "account_sid": "AC0123456789abcdef0123456789abcdef",
                      "created_at": "2026-09-14T08:15:00Z",
                      "updated_at": "2026-09-14T08:15:00Z"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request sent a `Dew-Act-As` header. Admin actions can't act as a user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Dew-Act-As can't be used for admin actions."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or admin access isn't allowed from the caller's network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "summary": "Missing permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "Network not allowed",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/sms-configs/{id}": {
      "get": {
        "operationId": "getSmsConfig",
        "summary": "Get an SMS setup",
        "description": "Returns one text message provider setup. API keys are never returned. `needs_sender` is only filled in by the list.",
        "tags": [
          "Settings"
        ],
        "security": [
          {
            "token": [
              "settings:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "SMS setup ID."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/SmsConfig"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "8a2d4f60-1c3b-4e5a-9f7d-2b6c8e0a4d19",
                    "name": "Twilio",
                    "is_default": true,
                    "is_active": true,
                    "provider_type": "twilio",
                    "api_key_set": true,
                    "account_sid": "AC0123456789abcdef0123456789abcdef",
                    "created_at": "2026-09-14T08:15:00Z",
                    "updated_at": "2026-09-14T08:15:00Z"
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request sent a `Dew-Act-As` header. Admin actions can't act as a user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Dew-Act-As can't be used for admin actions."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or admin access isn't allowed from the caller's network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "summary": "Missing permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "Network not allowed",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such item.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "SMS configuration not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/global-settings": {
      "get": {
        "operationId": "getGlobalSettings",
        "summary": "Get server-wide settings",
        "description": "Returns the server-wide settings: storage, links, uploads, branding, email templates, security and alerts. Domains use these unless their own settings override them.",
        "tags": [
          "Settings"
        ],
        "security": [
          {
            "token": [
              "settings:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/GlobalSettings"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "storage_provider": "storage_default",
                    "max_upload_size_gb": 200,
                    "link_expiry_days": 30,
                    "max_link_lifetime_days": null,
                    "link_format_template": null,
                    "blocked_file_extensions": [
                      ".exe",
                      ".bat"
                    ],
                    "upload_limit_per_ip_mbps": null,
                    "upload_limit_total_mbps": null,
                    "upload_limit_exempt_local": true,
                    "enable_admin_ip_allowlist": false,
                    "admin_dashboard_allowed_ips": [],
                    "private_links_enabled": false,
                    "smtp_config_id": "3f1c2a9e-6b7d-4e21-9c0a-5d8e7f6a1b23",
                    "display_name": "Example Files",
                    "has_logo": true,
                    "logo_not_email_safe": false,
                    "has_favicon": true,
                    "has_background": false,
                    "accent_color": "#2563eb",
                    "email_invite_subject": null,
                    "email_invite_title": null,
                    "email_invite_body": null,
                    "email_alert_subject": null,
                    "email_alert_title": null,
                    "email_alert_body": null,
                    "email_footer": null,
                    "audit_log_retention_days": 365,
                    "received_file_retention_days": 30,
                    "allow_link_file_requests": true,
                    "require_link_upload_verification": true,
                    "avatars_enabled": true,
                    "personal_tokens_enabled": true,
                    "email_configured": true,
                    "disable_zip_browser": false,
                    "sanitize_windows_filenames": true,
                    "enable_sspr": true,
                    "require_2fa": "admins",
                    "password_policy_mode": "simple",
                    "password_min_length": 12,
                    "password_require_mixed_case": false,
                    "password_require_number": false,
                    "password_require_symbol": false,
                    "password_regex": "^.{12,}$",
                    "password_guidance": "At least 12 characters",
                    "link_not_found_behavior": "informative",
                    "link_not_found_redirect_url": null,
                    "session_lifetime_hours": 168,
                    "idle_timeout_enabled": false,
                    "idle_timeout_hours": 8,
                    "alert_cert_expiry_enabled": true,
                    "alert_storage_enabled": true,
                    "alert_storage_threshold_pct": 90,
                    "alert_storage_health_enabled": true,
                    "alert_license_enabled": true,
                    "alert_email_provider_enabled": true,
                    "alert_api_token_enabled": true,
                    "alert_version_enabled": false,
                    "update_check_enabled": true
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request sent a `Dew-Act-As` header. Admin actions can't act as a user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Dew-Act-As can't be used for admin actions."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or admin access isn't allowed from the caller's network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "summary": "Missing permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "Network not allowed",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/certs": {
      "get": {
        "operationId": "listCertificateFolders",
        "summary": "List certificate folders",
        "description": "Lists the certificate folders on the server that a domain can use, sorted by name. Only file locations are returned, never certificate or key contents. Let's Encrypt certificates are not listed here.",
        "tags": [
          "Settings"
        ],
        "security": [
          {
            "token": [
              "settings:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/CertificateFolder"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "cert_name": "files.example.com",
                      "cert_path": "certs/files.example.com/cert.pem",
                      "key_path": "certs/files.example.com/key.pem"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request sent a `Dew-Act-As` header. Admin actions can't act as a user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Dew-Act-As can't be used for admin actions."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or admin access isn't allowed from the caller's network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "summary": "Missing permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "Network not allowed",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/domains": {
      "get": {
        "operationId": "listDomains",
        "summary": "List domains",
        "description": "Lists every domain on the server, active or not, with its certificate status and storage provider override.",
        "tags": [
          "Settings"
        ],
        "security": [
          {
            "token": [
              "settings:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Domain"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "c7e2a1d4-5b6f-4a39-8e10-2f3d4c5b6a71",
                      "hostname": "files.example.com",
                      "is_primary": true,
                      "is_active": true,
                      "is_verified": true,
                      "verified_at": "2026-09-14T08:30:00Z",
                      "last_verified_at": "2026-10-03T06:00:00Z",
                      "cert_name": "files.example.com",
                      "cert_mode": "letsencrypt",
                      "acme_email": "admin@example.com",
                      "acme_last_attempt_at": "2026-09-30T02:10:00Z",
                      "acme_last_success_at": "2026-09-30T02:10:00Z",
                      "acme_cert_expires_at": "2026-12-29T00:00:00Z",
                      "hsts_enabled": true,
                      "created_at": "2026-09-14T08:20:00Z",
                      "updated_at": "2026-09-30T02:10:00Z",
                      "cert_status": {
                        "hostname": "files.example.com",
                        "cert_name": "files.example.com",
                        "cert_path": "",
                        "key_path": "",
                        "loaded": true,
                        "expires_at": "2026-12-29T00:00:00Z",
                        "not_after_unix": 1798531200,
                        "acme_email": "admin@example.com",
                        "acme_cert_expires_at": "2026-12-29T00:00:00Z",
                        "acme_last_success_at": "2026-09-30T02:10:00Z",
                        "acme_last_attempt_at": "2026-09-30T02:10:00Z",
                        "acme_renewal_window": "2026-11-29T00:00:00Z",
                        "auto_renew": true
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request sent a `Dew-Act-As` header. Admin actions can't act as a user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Dew-Act-As can't be used for admin actions."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or admin access isn't allowed from the caller's network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "summary": "Missing permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "Network not allowed",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/domains/public-ip": {
      "get": {
        "operationId": "getPublicIp",
        "summary": "Get the server's public IP address",
        "description": "Looks up the server's public IPv4 address, the address a domain's DNS A record should point to. The lookup asks Cloudflare (1.1.1.1) and waits up to 5 seconds. If it fails, `ipv4` is empty.",
        "tags": [
          "Settings"
        ],
        "security": [
          {
            "token": [
              "settings:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/PublicIp"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "ipv4": "203.0.113.10"
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request sent a `Dew-Act-As` header. Admin actions can't act as a user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Dew-Act-As can't be used for admin actions."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or admin access isn't allowed from the caller's network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "summary": "Missing permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "Network not allowed",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/domains/{id}/cert-status": {
      "get": {
        "operationId": "getDomainCertStatus",
        "summary": "Get a domain's certificate status",
        "description": "Returns the certificate a domain serves, when it expires and, for Let's Encrypt, the latest issuance attempt. For Let's Encrypt, the server reads the current certificate and saves its expiry date if it changed.",
        "tags": [
          "Settings"
        ],
        "security": [
          {
            "token": [
              "settings:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Domain ID."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/DomainCertStatus"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "hostname": "files.example.com",
                    "cert_name": "files.example.com",
                    "cert_path": "",
                    "key_path": "",
                    "loaded": true,
                    "status": "valid",
                    "issuer": "R11",
                    "dns_names": [
                      "files.example.com"
                    ],
                    "not_after_unix": 1798531200,
                    "expires_at": "2026-12-29T00:00:00Z",
                    "acme_email": "admin@example.com",
                    "acme_cert_expires_at": "2026-12-29T00:00:00Z",
                    "acme_last_success_at": "2026-09-30T02:10:00Z",
                    "acme_last_attempt_at": "2026-09-30T02:10:00Z",
                    "acme_renewal_window": "2026-11-29T00:00:00Z",
                    "auto_renew": true
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request sent a `Dew-Act-As` header. Admin actions can't act as a user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Dew-Act-As can't be used for admin actions."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or admin access isn't allowed from the caller's network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "summary": "Missing permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "Network not allowed",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such item.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "Domain not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/domains/{id}/settings": {
      "get": {
        "operationId": "getDomainSettings",
        "summary": "Get a domain's settings",
        "description": "Returns the settings a domain overrides. A null field means the domain uses the server-wide setting. A domain with no settings of its own returns every field unset, and so does an unknown domain ID.",
        "tags": [
          "Settings"
        ],
        "security": [
          {
            "token": [
              "settings:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Domain ID."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/DomainSettings"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "domain_id": "c7e2a1d4-5b6f-4a39-8e10-2f3d4c5b6a71",
                    "storage_provider": null,
                    "max_upload_size_gb": 50,
                    "link_expiry_days": 14,
                    "max_link_lifetime_days": null,
                    "link_format_template": null,
                    "blocked_file_extensions": [],
                    "display_name": "Example Legal",
                    "has_logo": true,
                    "logo_not_email_safe": false,
                    "has_favicon": false,
                    "has_background": false,
                    "accent_color": "#0f766e",
                    "email_invite_subject": null,
                    "email_invite_title": null,
                    "email_invite_body": null,
                    "email_alert_subject": null,
                    "email_alert_title": null,
                    "email_alert_body": null,
                    "email_footer": null,
                    "disable_zip_browser": null,
                    "sanitize_windows_filenames": null,
                    "link_not_found_behavior": null,
                    "link_not_found_redirect_url": null
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request sent a `Dew-Act-As` header. Admin actions can't act as a user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Dew-Act-As can't be used for admin actions."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or admin access isn't allowed from the caller's network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "summary": "Missing permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "Network not allowed",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/private-allowlists": {
      "get": {
        "operationId": "listPrivateAllowlists",
        "summary": "List private link networks",
        "description": "Lists the networks allowed to open private links, server-wide lists first, up to 500. With `domain_id`, returns the server-wide lists and that domain's lists.",
        "tags": [
          "Settings"
        ],
        "security": [
          {
            "token": [
              "settings:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "domain_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only server-wide lists and the lists of this domain."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/PrivateAllowlist"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "5e9b0c12-7a3d-4f8e-b1c2-6d4e8f0a2b37",
                      "name": "Office network",
                      "description": "HQ and VPN",
                      "cidr_ranges": [
                        "203.0.113.0/24",
                        "10.8.0.0/16"
                      ],
                      "is_active": true,
                      "is_global": true,
                      "created_at": "2026-09-15T09:00:00Z",
                      "updated_at": "2026-09-15T09:00:00Z"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request sent a `Dew-Act-As` header. Admin actions can't act as a user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Dew-Act-As can't be used for admin actions."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or admin access isn't allowed from the caller's network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "summary": "Missing permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "Network not allowed",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/private-allowlists/{id}": {
      "get": {
        "operationId": "getPrivateAllowlist",
        "summary": "Get a private link network list",
        "description": "Returns one list of networks allowed to open private links.",
        "tags": [
          "Settings"
        ],
        "security": [
          {
            "token": [
              "settings:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "List ID."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/PrivateAllowlist"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "5e9b0c12-7a3d-4f8e-b1c2-6d4e8f0a2b37",
                    "name": "Office network",
                    "description": "HQ and VPN",
                    "cidr_ranges": [
                      "203.0.113.0/24",
                      "10.8.0.0/16"
                    ],
                    "is_active": true,
                    "is_global": true,
                    "created_at": "2026-09-15T09:00:00Z",
                    "updated_at": "2026-09-15T09:00:00Z"
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request sent a `Dew-Act-As` header. Admin actions can't act as a user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Dew-Act-As can't be used for admin actions."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or admin access isn't allowed from the caller's network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "summary": "Missing permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "Network not allowed",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such item.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "Allowlist not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/storage-providers": {
      "get": {
        "operationId": "listStorageProviders",
        "summary": "List storage providers",
        "description": "Lists every storage provider with its usage and, for local storage, disk space and health. Access keys and secret keys are never returned. Local storage that was out of service and is healthy again goes back into service.",
        "tags": [
          "Settings"
        ],
        "security": [
          {
            "token": [
              "settings:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/StorageProvider"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "storage_default",
                      "name": "Default local storage",
                      "provider_type": "local",
                      "base_path": "/app/storage",
                      "is_active": true,
                      "direct_upload_enabled": false,
                      "total_bytes": 1000204886016,
                      "used_by_dew": 52613349376,
                      "free_bytes": 812345671680,
                      "file_count": 1843,
                      "created_at": "2026-09-14T08:00:00Z",
                      "is_global_default": true,
                      "domain_override_count": 0,
                      "active_session_count": 0,
                      "health_status": "ok",
                      "is_registered": true
                    },
                    {
                      "id": "b4d7e2f1-9a8c-4b3e-a6d5-1c2f3e4d5a6b",
                      "name": "Cloudflare R2",
                      "provider_type": "cloudflare-r2",
                      "base_path": null,
                      "endpoint": "https://0123456789abcdef.r2.cloudflarestorage.com",
                      "region": "auto",
                      "bucket": "dew-files",
                      "path_style": true,
                      "is_active": true,
                      "direct_upload_enabled": true,
                      "total_bytes": -1,
                      "used_by_dew": 2147483648,
                      "free_bytes": -1,
                      "file_count": 120,
                      "created_at": "2026-09-20T12:00:00Z",
                      "is_global_default": false,
                      "domain_override_count": 1,
                      "active_session_count": 0,
                      "is_registered": true
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request sent a `Dew-Act-As` header. Admin actions can't act as a user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Dew-Act-As can't be used for admin actions."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or admin access isn't allowed from the caller's network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "summary": "Missing permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "Network not allowed",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/storage-providers/{id}": {
      "get": {
        "operationId": "getStorageProvider",
        "summary": "Get a storage provider",
        "description": "Returns one storage provider with its usage and, for local storage, disk space and health. Access keys and secret keys are never returned.",
        "tags": [
          "Settings"
        ],
        "security": [
          {
            "token": [
              "settings:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Storage provider ID."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/StorageProvider"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "b4d7e2f1-9a8c-4b3e-a6d5-1c2f3e4d5a6b",
                    "name": "Cloudflare R2",
                    "provider_type": "cloudflare-r2",
                    "base_path": null,
                    "endpoint": "https://0123456789abcdef.r2.cloudflarestorage.com",
                    "region": "auto",
                    "bucket": "dew-files",
                    "path_style": true,
                    "is_active": true,
                    "direct_upload_enabled": true,
                    "total_bytes": -1,
                    "used_by_dew": 2147483648,
                    "free_bytes": -1,
                    "file_count": 120,
                    "created_at": "2026-09-20T12:00:00Z",
                    "is_global_default": false,
                    "domain_override_count": 1,
                    "active_session_count": 0,
                    "is_registered": true
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request sent a `Dew-Act-As` header. Admin actions can't act as a user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Dew-Act-As can't be used for admin actions."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or admin access isn't allowed from the caller's network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "summary": "Missing permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "Network not allowed",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such item.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "Storage provider not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/storage-providers/mount-targets": {
      "get": {
        "operationId": "listStorageMountTargets",
        "summary": "List storage folders",
        "description": "Lists the folders the server can use for local storage: the built-in `/app/storage` and any folders mounted under `/mnt/dew`.",
        "tags": [
          "Settings"
        ],
        "security": [
          {
            "token": [
              "settings:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/StorageMountTargets"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "default_path": "/app/storage",
                    "extra_mount_prefix": "/mnt/dew",
                    "targets": [
                      {
                        "path": "/app/storage",
                        "fs_type": "bind",
                        "is_bind": true,
                        "writable": true,
                        "is_system": true
                      },
                      {
                        "path": "/mnt/dew/archive",
                        "fs_type": "ext4",
                        "is_bind": true,
                        "writable": true,
                        "is_system": false
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request sent a `Dew-Act-As` header. Admin actions can't act as a user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Dew-Act-As can't be used for admin actions."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, or admin access isn't allowed from the caller's network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "summary": "Missing permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "Network not allowed",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/sso/status": {
      "get": {
        "operationId": "getSsoStatus",
        "summary": "Get single sign-on status",
        "description": "Returns whether single sign-on is turned on, whether SAML can be used and how many connections exist.",
        "tags": [
          "Settings"
        ],
        "security": [
          {
            "token": [
              "settings:read"
            ]
          }
        ],
        "x-dew-feature": "sso.connections",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/SsoStatus"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "sso_enabled": true,
                    "oidc_available": true,
                    "saml_available": true,
                    "saml_error": "",
                    "connection_count": 1
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request sent a `Dew-Act-As` header. Admin actions can't act as a user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Dew-Act-As can't be used for admin actions."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, admin access isn't allowed from the caller's network, or the license doesn't include this feature.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "summary": "Missing permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "Network not allowed",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  },
                  "license": {
                    "summary": "Not in your plan",
                    "value": {
                      "success": false,
                      "error": "Feature Not Available",
                      "message": "This feature is available on the Pro and Enterprise plans."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/sso/connections": {
      "get": {
        "operationId": "listSsoConnections",
        "summary": "List single sign-on connections",
        "description": "Lists the single sign-on connections with the URLs to register at the identity provider. Client secrets and SCIM tokens are never returned.",
        "tags": [
          "Settings"
        ],
        "security": [
          {
            "token": [
              "settings:read"
            ]
          }
        ],
        "x-dew-feature": "sso.connections",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/SsoConnection"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "e1a2b3c4-d5e6-4f70-8192-a3b4c5d6e7f8",
                      "name": "Microsoft Entra ID",
                      "provider_type": "saml",
                      "provider": "entra",
                      "client_secret_set": false,
                      "saml_metadata_url": "https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/federationmetadata/2007-06/federationmetadata.xml",
                      "saml_idp_sso_url": "https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/saml2",
                      "saml_idp_entity_id": "https://sts.windows.net/00000000-0000-0000-0000-000000000000/",
                      "saml_idp_cert_count": 1,
                      "saml_idp_cert_expires_at": "2029-05-11T12:00:00Z",
                      "saml_certificates": [
                        {
                          "expires_at": "2029-05-11T12:00:00Z",
                          "additional": false
                        }
                      ],
                      "saml_attr_email": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
                      "email_domains": [
                        "example.com"
                      ],
                      "is_active": true,
                      "allow_user_creation": true,
                      "scim_enabled": true,
                      "scim_bearer_token_set": true,
                      "enforce_mode": "optional",
                      "created_at": "2026-09-16T10:00:00Z",
                      "updated_at": "2026-09-22T14:30:00Z",
                      "sp_acs_url": "https://files.example.com/api/sso/e1a2b3c4-d5e6-4f70-8192-a3b4c5d6e7f8/acs",
                      "sp_entity_id": "https://files.example.com/saml/sp/e1a2b3c4-d5e6-4f70-8192-a3b4c5d6e7f8",
                      "sp_metadata_url": "https://files.example.com/api/sso/e1a2b3c4-d5e6-4f70-8192-a3b4c5d6e7f8/sp-metadata",
                      "scim_base_url": "https://files.example.com/scim/v2"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request sent a `Dew-Act-As` header. Admin actions can't act as a user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Dew-Act-As can't be used for admin actions."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, admin access isn't allowed from the caller's network, or the license doesn't include this feature.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "summary": "Missing permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "Network not allowed",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  },
                  "license": {
                    "summary": "Not in your plan",
                    "value": {
                      "success": false,
                      "error": "Feature Not Available",
                      "message": "This feature is available on the Pro and Enterprise plans."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/sso/connections/{id}": {
      "get": {
        "operationId": "getSsoConnection",
        "summary": "Get a single sign-on connection",
        "description": "Returns one single sign-on connection with the URLs to register at the identity provider. Client secrets and SCIM tokens are never returned.",
        "tags": [
          "Settings"
        ],
        "security": [
          {
            "token": [
              "settings:read"
            ]
          }
        ],
        "x-dew-feature": "sso.connections",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Single sign-on connection ID."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/SsoConnection"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "e1a2b3c4-d5e6-4f70-8192-a3b4c5d6e7f8",
                    "name": "Microsoft Entra ID",
                    "provider_type": "saml",
                    "provider": "entra",
                    "client_secret_set": false,
                    "saml_metadata_url": "https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/federationmetadata/2007-06/federationmetadata.xml",
                    "saml_idp_sso_url": "https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/saml2",
                    "saml_idp_entity_id": "https://sts.windows.net/00000000-0000-0000-0000-000000000000/",
                    "saml_idp_cert_count": 1,
                    "saml_idp_cert_expires_at": "2029-05-11T12:00:00Z",
                    "saml_certificates": [
                      {
                        "expires_at": "2029-05-11T12:00:00Z",
                        "additional": false
                      }
                    ],
                    "saml_attr_email": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
                    "email_domains": [
                      "example.com"
                    ],
                    "is_active": true,
                    "allow_user_creation": true,
                    "scim_enabled": true,
                    "scim_bearer_token_set": true,
                    "enforce_mode": "optional",
                    "created_at": "2026-09-16T10:00:00Z",
                    "updated_at": "2026-09-22T14:30:00Z",
                    "sp_acs_url": "https://files.example.com/api/sso/e1a2b3c4-d5e6-4f70-8192-a3b4c5d6e7f8/acs",
                    "sp_entity_id": "https://files.example.com/saml/sp/e1a2b3c4-d5e6-4f70-8192-a3b4c5d6e7f8",
                    "sp_metadata_url": "https://files.example.com/api/sso/e1a2b3c4-d5e6-4f70-8192-a3b4c5d6e7f8/sp-metadata",
                    "scim_base_url": "https://files.example.com/scim/v2"
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request sent a `Dew-Act-As` header. Admin actions can't act as a user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Dew-Act-As can't be used for admin actions."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, admin access isn't allowed from the caller's network, or the license doesn't include this feature.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "summary": "Missing permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "Network not allowed",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  },
                  "license": {
                    "summary": "Not in your plan",
                    "value": {
                      "success": false,
                      "error": "Feature Not Available",
                      "message": "This feature is available on the Pro and Enterprise plans."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such item.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "SSO connection not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/sso/connections/{id}/delete-impact": {
      "get": {
        "operationId": "getSsoConnectionDeleteImpact",
        "summary": "Preview deleting a single sign-on connection",
        "description": "Counts the users who sign in through this connection and would be affected if it were deleted.",
        "tags": [
          "Settings"
        ],
        "security": [
          {
            "token": [
              "settings:read"
            ]
          }
        ],
        "x-dew-feature": "sso.connections",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Single sign-on connection ID."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/SsoConnectionDeleteImpact"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "connection_id": "e1a2b3c4-d5e6-4f70-8192-a3b4c5d6e7f8",
                    "attached_user_count": 42,
                    "active_user_count": 39,
                    "inactive_user_count": 3
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request sent a `Dew-Act-As` header. Admin actions can't act as a user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Dew-Act-As can't be used for admin actions."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, admin access isn't allowed from the caller's network, or the license doesn't include this feature.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "summary": "Missing permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "Network not allowed",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  },
                  "license": {
                    "summary": "Not in your plan",
                    "value": {
                      "success": false,
                      "error": "Feature Not Available",
                      "message": "This feature is available on the Pro and Enterprise plans."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such item.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "SSO connection not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/sso/connections/{id}/enforcement-impact": {
      "get": {
        "operationId": "getSsoEnforcementImpact",
        "summary": "Preview requiring single sign-on",
        "description": "Counts the users who would no longer be able to sign in with a password if this connection's `enforce_mode` were set to `required`.",
        "tags": [
          "Settings"
        ],
        "security": [
          {
            "token": [
              "settings:read"
            ]
          }
        ],
        "x-dew-feature": "sso.connections",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Single sign-on connection ID."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/SsoEnforcementImpact"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "affected_user_count": 12
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request sent a `Dew-Act-As` header. Admin actions can't act as a user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Dew-Act-As can't be used for admin actions."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, admin access isn't allowed from the caller's network, or the license doesn't include this feature.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "summary": "Missing permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "Network not allowed",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  },
                  "license": {
                    "summary": "Not in your plan",
                    "value": {
                      "success": false,
                      "error": "Feature Not Available",
                      "message": "This feature is available on the Pro and Enterprise plans."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such item.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Not Found",
                  "message": "SSO connection not found"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/sso/events": {
      "get": {
        "operationId": "listSsoEvents",
        "summary": "List single sign-on events",
        "description": "Lists recent single sign-on and SCIM events, newest first: sign-ins, refused sign-ins with the reason, users created or linked, and SCIM changes.",
        "tags": [
          "Settings"
        ],
        "security": [
          {
            "token": [
              "settings:read"
            ]
          }
        ],
        "x-dew-feature": "sso.connections",
        "parameters": [
          {
            "name": "connection_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only events of this connection."
          },
          {
            "name": "event_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "login",
                "login_failed",
                "user_provisioned",
                "user_linked",
                "scim_provision",
                "scim_deprovision",
                "scim_group_update"
              ]
            },
            "description": "Only events of this type."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            },
            "description": "Most events to return. A value outside 1 to 500 is ignored and 100 are returned."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/SsoEvent"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": 1042,
                      "connection_id": "e1a2b3c4-d5e6-4f70-8192-a3b4c5d6e7f8",
                      "event_type": "login_failed",
                      "user_email": "bob@example.com",
                      "external_id": "bob@example.com",
                      "details": {
                        "reason": "no_access_for_new_account"
                      },
                      "created_at": "2026-10-03T09:14:22Z"
                    },
                    {
                      "id": 1041,
                      "connection_id": "e1a2b3c4-d5e6-4f70-8192-a3b4c5d6e7f8",
                      "event_type": "login",
                      "user_email": "anna@example.com",
                      "external_id": "anna@example.com",
                      "details": {
                        "action": "login_success",
                        "user_id": "2b3c4d5e-6f70-4812-9a3b-4c5d6e7f8091"
                      },
                      "created_at": "2026-10-03T09:10:05Z"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request sent a `Dew-Act-As` header. Admin actions can't act as a user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "success": false,
                  "error": "Bad Request",
                  "message": "Dew-Act-As can't be used for admin actions."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, admin access isn't allowed from the caller's network, or the license doesn't include this feature.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scope": {
                    "summary": "Missing permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "network": {
                    "summary": "Network not allowed",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  },
                  "license": {
                    "summary": "Not in your plan",
                    "value": {
                      "success": false,
                      "error": "Feature Not Available",
                      "message": "This feature is available on the Pro and Enterprise plans."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/audit-logs": {
      "get": {
        "operationId": "listAuditEvents",
        "summary": "List audit events",
        "description": "Returns audit events matching the filters, newest first, one page at a time. To read every event as it happens, use the audit feed instead.",
        "tags": [
          "Audit log"
        ],
        "security": [
          {
            "token": [
              "audit:read"
            ]
          }
        ],
        "x-dew-feature": "audit.logs",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Matches whole words in the target name, description and actor email, or any part of the target name or actor email (when the term has 3 letters or digits in a row)."
          },
          {
            "name": "event_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated event types. A value without a dot matches a whole category: `file,user.created` matches every `file.*` event and `user.created`.",
            "example": "file,user.created"
          },
          {
            "name": "severity",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "info",
                "warn"
              ]
            },
            "description": "Only events with this severity."
          },
          {
            "name": "outcome",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "success",
                "failure"
              ]
            },
            "description": "Only events with this outcome."
          },
          {
            "name": "actor_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only events by this actor (`actor.id`)."
          },
          {
            "name": "target_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only events on this kind of target (`target.type`), such as `file`."
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only events at or after this time (RFC 3339).",
            "example": "2026-10-01T00:00:00Z"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only events at or before this time (RFC 3339).",
            "example": "2026-10-01T23:59:59Z"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "The `next_cursor` of the previous page. Leave out for the newest events."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            },
            "description": "Most events per page. Larger values return 200."
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/AuditEventPage"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "entries": [
                      {
                        "id": 48214,
                        "event_id": "9a1d7e40-2c3b-4f58-8d6e-0b7c1a2f3e45",
                        "timestamp": "2026-10-02T14:05:42.508000Z",
                        "event_type": "auth.signed_in",
                        "category": "auth",
                        "outcome": "failure",
                        "reason": "wrong_password",
                        "severity": "warn",
                        "description": "Sign-in failed",
                        "actor": {
                          "type": "user",
                          "id": "6b1f0c2e-4d3a-4e5b-9c8d-7a6f5e4d3c2b",
                          "email": "anna@example.com"
                        },
                        "target": {
                          "type": "user",
                          "id": "6b1f0c2e-4d3a-4e5b-9c8d-7a6f5e4d3c2b",
                          "name": "anna@example.com"
                        },
                        "client_ip": "198.51.100.7",
                        "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5)",
                        "request_id": "c81e728d9d4c2f636f067f89cc14862c",
                        "metadata": {
                          "method": "password"
                        }
                      },
                      {
                        "id": 48213,
                        "event_id": "3f6c2a1e-8b4d-4c7a-9e21-5d0f7b6a9c34",
                        "timestamp": "2026-10-02T14:03:11.120000Z",
                        "event_type": "file.downloaded",
                        "category": "file",
                        "outcome": "success",
                        "severity": "info",
                        "description": "File downloaded",
                        "actor": {
                          "type": "external",
                          "email": "bob@example.com"
                        },
                        "target": {
                          "type": "file",
                          "id": "kT9xQ2aZ",
                          "name": "Q4 invoices.pdf"
                        },
                        "domain": "files.example.com",
                        "client_ip": "203.0.113.24",
                        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
                        "request_id": "a3f8b2c1d4e5f60718293a4b5c6d7e8f",
                        "metadata": {
                          "via": "link",
                          "size_bytes": 2483021,
                          "owner_email": "anna@example.com"
                        }
                      }
                    ],
                    "next_cursor": "2026-10-02T14:03:11.12Z,48213",
                    "has_more": true
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid; `message` says what to change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "actAs": {
                    "summary": "A Dew-Act-As header was sent",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Dew-Act-As can't be used for admin actions."
                    }
                  },
                  "invalid1": {
                    "summary": "`from` is not an RFC 3339 time",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Invalid 'from' date: must be RFC3339 (e.g. 2026-07-12T00:00:00Z)"
                    }
                  },
                  "invalid2": {
                    "summary": "`to` is not an RFC 3339 time",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Invalid 'to' date: must be RFC3339 (e.g. 2026-07-12T23:59:59Z)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, is a personal token, or the caller's network is not allowed. Also returned when the license doesn't include audit logs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scopeMissing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "personalToken": {
                    "summary": "A personal token was used",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Personal API tokens can't be used for admin actions."
                    }
                  },
                  "network": {
                    "summary": "The admin IP allowlist doesn't include the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  },
                  "featureNotAvailable": {
                    "summary": "The license doesn't include audit logs",
                    "value": {
                      "success": false,
                      "error": "Feature Not Available",
                      "message": "This feature is available on the Enterprise plan."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/audit-logs/export": {
      "get": {
        "operationId": "exportAuditEvents",
        "summary": "Export audit events",
        "description": "Downloads every audit event matching the filters as NDJSON, newest first, with no limit on the number of events. Each export is itself recorded in the audit log as `audit.exported`.",
        "tags": [
          "Audit log"
        ],
        "security": [
          {
            "token": [
              "audit:read"
            ]
          }
        ],
        "x-dew-feature": "audit.logs",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Matches whole words in the target name, description and actor email, or any part of the target name or actor email (when the term has 3 letters or digits in a row)."
          },
          {
            "name": "event_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated event types. A value without a dot matches a whole category: `file,user.created` matches every `file.*` event and `user.created`.",
            "example": "file,user.created"
          },
          {
            "name": "severity",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "info",
                "warn"
              ]
            },
            "description": "Only events with this severity."
          },
          {
            "name": "outcome",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "success",
                "failure"
              ]
            },
            "description": "Only events with this outcome."
          },
          {
            "name": "actor_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only events by this actor (`actor.id`)."
          },
          {
            "name": "target_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only events on this kind of target (`target.type`), such as `file`."
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only events at or after this time (RFC 3339).",
            "example": "2026-10-01T00:00:00Z"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only events at or before this time (RFC 3339).",
            "example": "2026-10-01T23:59:59Z"
          }
        ],
        "responses": {
          "200": {
            "description": "The events, as a download named `audit-logs.ndjson`. One JSON record per line. If the export fails after it started, the last line is `{\"error\":\"export_incomplete\",\"message\":\"This export is incomplete. Try exporting again.\"}`.",
            "headers": {
              "Content-Disposition": {
                "schema": {
                  "type": "string"
                },
                "description": "`attachment; filename=audit-logs.ndjson`"
              }
            },
            "content": {
              "application/x-ndjson": {
                "schema": {
                  "$ref": "#/components/schemas/AuditEvent"
                },
                "example": "{\"id\":48214,\"event_id\":\"9a1d7e40-2c3b-4f58-8d6e-0b7c1a2f3e45\",\"timestamp\":\"2026-10-02T14:05:42.508000Z\",\"event_type\":\"auth.signed_in\",\"category\":\"auth\",\"outcome\":\"failure\",\"reason\":\"wrong_password\",\"severity\":\"warn\",\"description\":\"Sign-in failed\",\"actor\":{\"type\":\"user\",\"id\":\"6b1f0c2e-4d3a-4e5b-9c8d-7a6f5e4d3c2b\",\"email\":\"anna@example.com\"},\"target\":{\"type\":\"user\",\"id\":\"6b1f0c2e-4d3a-4e5b-9c8d-7a6f5e4d3c2b\",\"name\":\"anna@example.com\"},\"client_ip\":\"198.51.100.7\",\"user_agent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5)\",\"request_id\":\"c81e728d9d4c2f636f067f89cc14862c\",\"metadata\":{\"method\":\"password\"}}\n{\"id\":48213,\"event_id\":\"3f6c2a1e-8b4d-4c7a-9e21-5d0f7b6a9c34\",\"timestamp\":\"2026-10-02T14:03:11.120000Z\",\"event_type\":\"file.downloaded\",\"category\":\"file\",\"outcome\":\"success\",\"severity\":\"info\",\"description\":\"File downloaded\",\"actor\":{\"type\":\"external\",\"email\":\"bob@example.com\"},\"target\":{\"type\":\"file\",\"id\":\"kT9xQ2aZ\",\"name\":\"Q4 invoices.pdf\"},\"domain\":\"files.example.com\",\"client_ip\":\"203.0.113.24\",\"user_agent\":\"Mozilla/5.0 (Windows NT 10.0; Win64; x64)\",\"request_id\":\"a3f8b2c1d4e5f60718293a4b5c6d7e8f\",\"metadata\":{\"via\":\"link\",\"size_bytes\":2483021,\"owner_email\":\"anna@example.com\"}}\n"
              }
            }
          },
          "400": {
            "description": "The request is invalid; `message` says what to change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "actAs": {
                    "summary": "A Dew-Act-As header was sent",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Dew-Act-As can't be used for admin actions."
                    }
                  },
                  "invalid1": {
                    "summary": "`from` is not an RFC 3339 time",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Invalid 'from' date: must be RFC3339 (e.g. 2026-07-12T00:00:00Z)"
                    }
                  },
                  "invalid2": {
                    "summary": "`to` is not an RFC 3339 time",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Invalid 'to' date: must be RFC3339 (e.g. 2026-07-12T23:59:59Z)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, is a personal token, or the caller's network is not allowed. Also returned when the license doesn't include audit logs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scopeMissing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "personalToken": {
                    "summary": "A personal token was used",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Personal API tokens can't be used for admin actions."
                    }
                  },
                  "network": {
                    "summary": "The admin IP allowlist doesn't include the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  },
                  "featureNotAvailable": {
                    "summary": "The license doesn't include audit logs",
                    "value": {
                      "success": false,
                      "error": "Feature Not Available",
                      "message": "This feature is available on the Enterprise plan."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/audit-logs/stats": {
      "get": {
        "operationId": "getAuditEventStats",
        "summary": "Count audit events by category",
        "description": "Returns how many audit events each category had in the last 24 hours, most first.",
        "tags": [
          "Audit log"
        ],
        "security": [
          {
            "token": [
              "audit:read"
            ]
          }
        ],
        "x-dew-feature": "audit.logs",
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/AuditCategoryCount"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "category": "file",
                      "count": 412
                    },
                    {
                      "category": "auth",
                      "count": 96
                    },
                    {
                      "category": "file_request",
                      "count": 37
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid; `message` says what to change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "actAs": {
                    "summary": "A Dew-Act-As header was sent",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Dew-Act-As can't be used for admin actions."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, is a personal token, or the caller's network is not allowed. Also returned when the license doesn't include audit logs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scopeMissing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "personalToken": {
                    "summary": "A personal token was used",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Personal API tokens can't be used for admin actions."
                    }
                  },
                  "network": {
                    "summary": "The admin IP allowlist doesn't include the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  },
                  "featureNotAvailable": {
                    "summary": "The license doesn't include audit logs",
                    "value": {
                      "success": false,
                      "error": "Feature Not Available",
                      "message": "This feature is available on the Enterprise plan."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/audit-logs/feed": {
      "get": {
        "operationId": "getAuditFeed",
        "summary": "Read the audit feed",
        "description": "Returns every audit event with an `id` above `after_id`, oldest first, for a SIEM to collect. Store `next_after_id` and send it as `after_id` on the next call; poll again right away while `has_more` is true. The feed never skips an event: no event appears later with an `id` below one you have already read. Reading the feed is not recorded in the audit log.",
        "tags": [
          "Audit log"
        ],
        "security": [
          {
            "token": [
              "audit:read"
            ]
          }
        ],
        "x-dew-feature": "audit.logs",
        "parameters": [
          {
            "name": "after_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0,
              "default": 0
            },
            "description": "Return events with an `id` above this. Start at 0, then send the `next_after_id` of the previous response."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1000,
              "default": 500
            },
            "description": "Most events to return."
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/AuditFeedPage"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "entries": [
                      {
                        "id": 48213,
                        "event_id": "3f6c2a1e-8b4d-4c7a-9e21-5d0f7b6a9c34",
                        "timestamp": "2026-10-02T14:03:11.120000Z",
                        "event_type": "file.downloaded",
                        "category": "file",
                        "outcome": "success",
                        "severity": "info",
                        "description": "File downloaded",
                        "actor": {
                          "type": "external",
                          "email": "bob@example.com"
                        },
                        "target": {
                          "type": "file",
                          "id": "kT9xQ2aZ",
                          "name": "Q4 invoices.pdf"
                        },
                        "domain": "files.example.com",
                        "client_ip": "203.0.113.24",
                        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
                        "request_id": "a3f8b2c1d4e5f60718293a4b5c6d7e8f",
                        "metadata": {
                          "via": "link",
                          "size_bytes": 2483021,
                          "owner_email": "anna@example.com"
                        }
                      },
                      {
                        "id": 48214,
                        "event_id": "9a1d7e40-2c3b-4f58-8d6e-0b7c1a2f3e45",
                        "timestamp": "2026-10-02T14:05:42.508000Z",
                        "event_type": "auth.signed_in",
                        "category": "auth",
                        "outcome": "failure",
                        "reason": "wrong_password",
                        "severity": "warn",
                        "description": "Sign-in failed",
                        "actor": {
                          "type": "user",
                          "id": "6b1f0c2e-4d3a-4e5b-9c8d-7a6f5e4d3c2b",
                          "email": "anna@example.com"
                        },
                        "target": {
                          "type": "user",
                          "id": "6b1f0c2e-4d3a-4e5b-9c8d-7a6f5e4d3c2b",
                          "name": "anna@example.com"
                        },
                        "client_ip": "198.51.100.7",
                        "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5)",
                        "request_id": "c81e728d9d4c2f636f067f89cc14862c",
                        "metadata": {
                          "method": "password"
                        }
                      }
                    ],
                    "next_after_id": 48214,
                    "has_more": false
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid; `message` says what to change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "actAs": {
                    "summary": "A Dew-Act-As header was sent",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Dew-Act-As can't be used for admin actions."
                    }
                  },
                  "invalid1": {
                    "summary": "`after_id` is not a whole number of 0 or more",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "after_id must be a whole number of 0 or more."
                    }
                  },
                  "invalid2": {
                    "summary": "`limit` is outside 1 to 1000",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "limit must be between 1 and 1000."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, is a personal token, or the caller's network is not allowed. Also returned when the license doesn't include audit logs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scopeMissing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "personalToken": {
                    "summary": "A personal token was used",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Personal API tokens can't be used for admin actions."
                    }
                  },
                  "network": {
                    "summary": "The admin IP allowlist doesn't include the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  },
                  "featureNotAvailable": {
                    "summary": "The license doesn't include audit logs",
                    "value": {
                      "success": false,
                      "error": "Feature Not Available",
                      "message": "This feature is available on the Enterprise plan."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/audit-logs/event-types": {
      "get": {
        "operationId": "listAuditEventTypes",
        "summary": "List audit event types",
        "description": "Returns every event type the audit log can hold, with its category, severity and labels, and the list of categories. Use it to set up parsers and filters.",
        "tags": [
          "Audit log"
        ],
        "security": [
          {
            "token": [
              "audit:read"
            ]
          }
        ],
        "x-dew-feature": "audit.logs",
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "required": [
                            "categories",
                            "event_types"
                          ],
                          "properties": {
                            "categories": {
                              "type": "array",
                              "items": {
                                "$ref": "#/components/schemas/AuditCategory"
                              }
                            },
                            "event_types": {
                              "type": "array",
                              "items": {
                                "$ref": "#/components/schemas/AuditEventType"
                              }
                            }
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "categories": [
                      {
                        "category": "auth",
                        "label": "Sign-in"
                      },
                      {
                        "category": "file",
                        "label": "Files and links"
                      }
                    ],
                    "event_types": [
                      {
                        "event_type": "auth.signed_in",
                        "category": "auth",
                        "severity": "info",
                        "label": "Signed in",
                        "failure_label": "Sign-in failed"
                      },
                      {
                        "event_type": "file.downloaded",
                        "category": "file",
                        "severity": "info",
                        "label": "File downloaded"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid; `message` says what to change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "actAs": {
                    "summary": "A Dew-Act-As header was sent",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Dew-Act-As can't be used for admin actions."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, is a personal token, or the caller's network is not allowed. Also returned when the license doesn't include audit logs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scopeMissing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "personalToken": {
                    "summary": "A personal token was used",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Personal API tokens can't be used for admin actions."
                    }
                  },
                  "network": {
                    "summary": "The admin IP allowlist doesn't include the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  },
                  "featureNotAvailable": {
                    "summary": "The license doesn't include audit logs",
                    "value": {
                      "success": false,
                      "error": "Feature Not Available",
                      "message": "This feature is available on the Enterprise plan."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/activity/feed": {
      "get": {
        "operationId": "getActivityFeed",
        "summary": "Read the activity feed",
        "description": "Returns file and file request events (`file.*` and `file_request.*`) on the service account's domains, oldest first, on every plan. Use it to react to uploads, downloads and files received through file requests. It works like the audit feed: store `next_after_id`, send it as `after_id` next time, and poll again right away while `has_more` is true. Service account tokens only.",
        "tags": [
          "Activity"
        ],
        "security": [
          {
            "token": [
              "activity:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "after_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0,
              "default": 0
            },
            "description": "Return events with an `id` above this. Start at 0, then send the `next_after_id` of the previous response."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1000,
              "default": 500
            },
            "description": "Most events to return."
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/AuditFeedPage"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "entries": [
                      {
                        "id": 48213,
                        "event_id": "3f6c2a1e-8b4d-4c7a-9e21-5d0f7b6a9c34",
                        "timestamp": "2026-10-02T14:03:11.120000Z",
                        "event_type": "file.downloaded",
                        "category": "file",
                        "outcome": "success",
                        "severity": "info",
                        "description": "File downloaded",
                        "actor": {
                          "type": "external",
                          "email": "bob@example.com"
                        },
                        "target": {
                          "type": "file",
                          "id": "kT9xQ2aZ",
                          "name": "Q4 invoices.pdf"
                        },
                        "domain": "files.example.com",
                        "client_ip": "203.0.113.24",
                        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
                        "request_id": "a3f8b2c1d4e5f60718293a4b5c6d7e8f",
                        "metadata": {
                          "via": "link",
                          "size_bytes": 2483021,
                          "owner_email": "anna@example.com"
                        }
                      }
                    ],
                    "next_after_id": 48213,
                    "has_more": false
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid; `message` says what to change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "actAs": {
                    "summary": "A Dew-Act-As header was sent",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Dew-Act-As can't be used for admin actions."
                    }
                  },
                  "invalid1": {
                    "summary": "`after_id` is not a whole number of 0 or more",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "after_id must be a whole number of 0 or more."
                    }
                  },
                  "invalid2": {
                    "summary": "`limit` is outside 1 to 1000",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "limit must be between 1 and 1000."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, is a personal token, the caller's network is not allowed, or the caller signed in as a person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scopeMissing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "personalToken": {
                    "summary": "A personal token was used",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Personal API tokens can't be used for admin actions."
                    }
                  },
                  "network": {
                    "summary": "The admin IP allowlist doesn't include the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  },
                  "notServiceAccount": {
                    "summary": "Called without a service account token",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Use a service account token to read the activity feed."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/system-logs": {
      "get": {
        "operationId": "listSystemLogs",
        "summary": "List system log entries",
        "description": "Returns the warnings and errors the server logged, newest first, one page at a time. An error reference a user quotes (`REF-a3f8b2c1`) can be pasted into `search`.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "token": [
              "system:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Matches words in the message. An error reference such as `REF-a3f8b2c1` (at least 4 characters after `REF-`) finds the entries of that request instead."
          },
          {
            "name": "level",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "warn",
                "error"
              ]
            },
            "description": "Only entries at this level."
          },
          {
            "name": "component",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only entries from this component. The components with recent entries are listed by `GET /api/admin/system-logs/stats`."
          },
          {
            "name": "error_code",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated error codes; matches any of them.",
            "example": "FILE_WRITE,FILE_REQUEST_EMAIL_SEND"
          },
          {
            "name": "acknowledged",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            },
            "description": "`true` for entries an admin marked as handled, `false` for the rest. Leave out for both."
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only entries at or after this time (RFC 3339).",
            "example": "2026-10-01T00:00:00Z"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only entries at or before this time (RFC 3339).",
            "example": "2026-10-01T23:59:59Z"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "The `next_cursor` of the previous page. Leave out for the newest entries."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            },
            "description": "Most entries per page. Larger values return 200."
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/SystemLogPage"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "entries": [
                      {
                        "id": 90211,
                        "timestamp": "2026-10-02T09:12:44.381Z",
                        "level": "error",
                        "message": "file write failed",
                        "component": "storage",
                        "error_code": "FILE_WRITE",
                        "request_id": "a3f8b2c1d4e5f60718293a4b5c6d7e8f",
                        "attributes": {
                          "provider": "S3 primary"
                        }
                      }
                    ],
                    "next_cursor": "",
                    "has_more": false
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid; `message` says what to change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "actAs": {
                    "summary": "A Dew-Act-As header was sent",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Dew-Act-As can't be used for admin actions."
                    }
                  },
                  "invalid1": {
                    "summary": "`from` is not an RFC 3339 time",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Invalid 'from' date: must be RFC3339 (e.g. 2026-07-12T00:00:00Z)"
                    }
                  },
                  "invalid2": {
                    "summary": "`to` is not an RFC 3339 time",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Invalid 'to' date: must be RFC3339 (e.g. 2026-07-12T23:59:59Z)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, is a personal token, or the caller's network is not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scopeMissing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "personalToken": {
                    "summary": "A personal token was used",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Personal API tokens can't be used for admin actions."
                    }
                  },
                  "network": {
                    "summary": "The admin IP allowlist doesn't include the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/system-logs/export": {
      "get": {
        "operationId": "exportSystemLogs",
        "summary": "Export system log entries",
        "description": "Downloads the newest 10,000 system log entries matching the filters as NDJSON, newest first. Each export is recorded in the audit log as `log.exported`.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "token": [
              "system:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Matches words in the message. An error reference such as `REF-a3f8b2c1` (at least 4 characters after `REF-`) finds the entries of that request instead."
          },
          {
            "name": "level",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "warn",
                "error"
              ]
            },
            "description": "Only entries at this level."
          },
          {
            "name": "component",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only entries from this component. The components with recent entries are listed by `GET /api/admin/system-logs/stats`."
          },
          {
            "name": "error_code",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated error codes; matches any of them.",
            "example": "FILE_WRITE,FILE_REQUEST_EMAIL_SEND"
          },
          {
            "name": "acknowledged",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            },
            "description": "`true` for entries an admin marked as handled, `false` for the rest. Leave out for both."
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only entries at or after this time (RFC 3339).",
            "example": "2026-10-01T00:00:00Z"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only entries at or before this time (RFC 3339).",
            "example": "2026-10-01T23:59:59Z"
          }
        ],
        "responses": {
          "200": {
            "description": "The entries, as a download named `system-logs-YYYY-MM-DD.ndjson`. One JSON record per line. If the export fails after it started, the last line is `{\"error\":\"export_incomplete\",\"message\":\"This export is incomplete. Try exporting again.\"}`.",
            "headers": {
              "Content-Disposition": {
                "schema": {
                  "type": "string"
                },
                "description": "`attachment; filename=system-logs-2026-10-02.ndjson`"
              }
            },
            "content": {
              "application/x-ndjson": {
                "schema": {
                  "$ref": "#/components/schemas/SystemLogEntry"
                },
                "example": "{\"id\":90211,\"timestamp\":\"2026-10-02T09:12:44.381Z\",\"level\":\"error\",\"message\":\"file write failed\",\"component\":\"storage\",\"error_code\":\"FILE_WRITE\",\"request_id\":\"a3f8b2c1d4e5f60718293a4b5c6d7e8f\",\"attributes\":{\"provider\":\"S3 primary\"}}\n"
              }
            }
          },
          "400": {
            "description": "The request is invalid; `message` says what to change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "actAs": {
                    "summary": "A Dew-Act-As header was sent",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Dew-Act-As can't be used for admin actions."
                    }
                  },
                  "invalid1": {
                    "summary": "`from` is not an RFC 3339 time",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Invalid 'from' date: must be RFC3339 (e.g. 2026-07-12T00:00:00Z)"
                    }
                  },
                  "invalid2": {
                    "summary": "`to` is not an RFC 3339 time",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Invalid 'to' date: must be RFC3339 (e.g. 2026-07-12T23:59:59Z)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, is a personal token, or the caller's network is not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scopeMissing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "personalToken": {
                    "summary": "A personal token was used",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Personal API tokens can't be used for admin actions."
                    }
                  },
                  "network": {
                    "summary": "The admin IP allowlist doesn't include the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/system-logs/stats": {
      "get": {
        "operationId": "getSystemLogStats",
        "summary": "Count system log entries by component",
        "description": "Returns how many warnings and errors each component logged in the last 24 hours, most first.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "token": [
              "system:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/SystemLogComponentCount"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "component": "storage",
                      "count": 14
                    },
                    {
                      "component": "email",
                      "count": 3
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid; `message` says what to change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "actAs": {
                    "summary": "A Dew-Act-As header was sent",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Dew-Act-As can't be used for admin actions."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, is a personal token, or the caller's network is not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scopeMissing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "personalToken": {
                    "summary": "A personal token was used",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Personal API tokens can't be used for admin actions."
                    }
                  },
                  "network": {
                    "summary": "The admin IP allowlist doesn't include the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/system-logs/error-codes": {
      "get": {
        "operationId": "listSystemLogErrorCodes",
        "summary": "List error codes",
        "description": "Returns every error code a system log entry can carry, sorted, for the `error_code` filter.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "token": [
              "system:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    "ACCESS_LOG_READ",
                    "ACME_CERT_UNAVAILABLE",
                    "ACME_DOMAIN_LIST"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid; `message` says what to change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "actAs": {
                    "summary": "A Dew-Act-As header was sent",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Dew-Act-As can't be used for admin actions."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, is a personal token, or the caller's network is not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scopeMissing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "personalToken": {
                    "summary": "A personal token was used",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Personal API tokens can't be used for admin actions."
                    }
                  },
                  "network": {
                    "summary": "The admin IP allowlist doesn't include the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/system/diagnostics": {
      "get": {
        "operationId": "getDiagnostics",
        "summary": "Get server diagnostics",
        "description": "Returns the server's version, uptime, database version, counts of users, files and domains, active storage providers and network setup.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "token": [
              "system:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/Diagnostics"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "server_version": "1.4.0",
                    "os": "linux/amd64",
                    "uptime_seconds": 432180,
                    "postgres_version": "18.0",
                    "total_users": 42,
                    "total_files": 1830,
                    "total_domains": 2,
                    "storage_providers": [
                      {
                        "id": "0b7c1a2f-3e45-4d6e-8f90-1a2b3c4d5e6f",
                        "name": "S3 primary",
                        "provider_type": "s3",
                        "is_active": true
                      }
                    ],
                    "saml_sp_cert": {
                      "fingerprint": "4F:2A:9C:…:7B",
                      "expires_at": "2036-09-01T00:00:00Z"
                    },
                    "sso_enabled": true,
                    "log_level": "info",
                    "https_port": "443",
                    "public_https_port": "443",
                    "reverse_proxy": "none",
                    "trusted_proxies": [],
                    "trusted_proxies_from_env": false
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid; `message` says what to change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "actAs": {
                    "summary": "A Dew-Act-As header was sent",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Dew-Act-As can't be used for admin actions."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, is a personal token, or the caller's network is not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scopeMissing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "personalToken": {
                    "summary": "A personal token was used",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Personal API tokens can't be used for admin actions."
                    }
                  },
                  "network": {
                    "summary": "The admin IP allowlist doesn't include the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "post": {
        "operationId": "downloadSupportBundle",
        "summary": "Download a diagnostic report",
        "description": "Downloads a zip for support with `system-info.txt` (diagnostics, license, domains and certificates, email setup, disk space), `logs.jsonl` (the newest 10,000 warnings and errors) and, when access logging is on, `access.log` (today's access log). Email addresses and phone numbers are masked, and link IDs and other secrets are tagged. The download is recorded in the audit log as `support_bundle.downloaded`.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "token": [
              "system:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "The diagnostic report, as a download named `dew-diagnostics-YYYY-MM-DD.zip`.",
            "headers": {
              "Content-Disposition": {
                "schema": {
                  "type": "string"
                },
                "description": "`attachment; filename=dew-diagnostics-2026-10-02.zip`"
              }
            },
            "content": {
              "application/zip": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid; `message` says what to change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "actAs": {
                    "summary": "A Dew-Act-As header was sent",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Dew-Act-As can't be used for admin actions."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, is a personal token, or the caller's network is not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scopeMissing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "personalToken": {
                    "summary": "A personal token was used",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Personal API tokens can't be used for admin actions."
                    }
                  },
                  "network": {
                    "summary": "The admin IP allowlist doesn't include the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/system/overview": {
      "get": {
        "operationId": "getSystemOverview",
        "summary": "Get system health",
        "description": "Returns one check each for storage, email, certificates, the license and errors in the last 24 hours, worked out when you call it, plus the server's address, the size of stored files and whether a newer server version is available.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "token": [
              "system:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/SystemOverview"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "hostname": "files.example.com",
                    "checks": [
                      {
                        "area": "storage",
                        "status": "ok",
                        "summary": "Reachable"
                      },
                      {
                        "area": "email",
                        "status": "warn",
                        "summary": "Microsoft 365 secret expires in 9 days",
                        "link": "/admin/email"
                      },
                      {
                        "area": "certificates",
                        "status": "ok",
                        "summary": "Valid until Jan 12"
                      },
                      {
                        "area": "license",
                        "status": "ok",
                        "summary": "Pro · 12 of 25 users"
                      },
                      {
                        "area": "errors",
                        "status": "ok",
                        "summary": "No errors in the last 24 hours"
                      }
                    ],
                    "stored_bytes": 51758612480,
                    "available_version": "2026.11.1400",
                    "update_check_enabled": true,
                    "update_checked": true
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid; `message` says what to change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "actAs": {
                    "summary": "A Dew-Act-As header was sent",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Dew-Act-As can't be used for admin actions."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, is a personal token, or the caller's network is not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scopeMissing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "personalToken": {
                    "summary": "A personal token was used",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Personal API tokens can't be used for admin actions."
                    }
                  },
                  "network": {
                    "summary": "The admin IP allowlist doesn't include the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/access-logs": {
      "get": {
        "operationId": "getAccessLog",
        "summary": "Read an access log",
        "description": "Returns lines of an access log file as plain text, one request per line in Apache Combined format with the signed-in user's ID (or `-`) in the user field, ending in the duration and the request ID. By default it returns the last 500 lines of today's file. Reading a whole file (`tail=0`) is recorded in the audit log as `log.exported`.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "token": [
              "system:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "file",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "access.log"
            },
            "description": "The file to read: `access.log` for today, or a name from `GET /api/admin/access-logs/files`, such as `access-2026-10-01.log.gz`.",
            "example": "access-2026-10-01.log.gz"
          },
          {
            "name": "tail",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 5000,
              "default": 500
            },
            "description": "How many lines from the end to return. `0` returns the whole file; larger values return 5000."
          }
        ],
        "responses": {
          "200": {
            "description": "The log lines.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "example": "203.0.113.24 - 6b1f0c2e-4d3a-4e5b-9c8d-7a6f5e4d3c2b [02/Oct/2026:14:03:11 +0000] \"GET /api/files HTTP/1.1\" 200 5123 \"-\" \"Mozilla/5.0\" 12ms a3f8b2c1d4e5f60718293a4b5c6d7e8f\n"
              }
            }
          },
          "400": {
            "description": "The request is invalid; `message` says what to change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "actAs": {
                    "summary": "A Dew-Act-As header was sent",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Dew-Act-As can't be used for admin actions."
                    }
                  },
                  "invalid1": {
                    "summary": "`file` is not an access log file name",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Invalid log filename"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, is a personal token, or the caller's network is not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scopeMissing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "personalToken": {
                    "summary": "A personal token was used",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Personal API tokens can't be used for admin actions."
                    }
                  },
                  "network": {
                    "summary": "The admin IP allowlist doesn't include the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Access logging is turned off, or the file doesn't exist.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "disabled": {
                    "summary": "Access logging is turned off",
                    "value": {
                      "success": false,
                      "error": "Not Found",
                      "message": "Access logging is not enabled"
                    }
                  },
                  "noFile": {
                    "summary": "No such file",
                    "value": {
                      "success": false,
                      "error": "Not Found",
                      "message": "Log file not found"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/access-logs/files": {
      "get": {
        "operationId": "listAccessLogFiles",
        "summary": "List access log files",
        "description": "Returns the access log files kept on the server: today's `access.log` and one file per earlier day, compressed (`.gz`) after a day. The list is empty when access logging is turned off.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "token": [
              "system:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/AccessLogFile"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "name": "access.log",
                      "date": "today",
                      "size": 184320
                    },
                    {
                      "name": "access-2026-10-01.log.gz",
                      "date": "2026-10-01",
                      "size": 40211
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid; `message` says what to change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "actAs": {
                    "summary": "A Dew-Act-As header was sent",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Dew-Act-As can't be used for admin actions."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, is a personal token, or the caller's network is not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scopeMissing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "personalToken": {
                    "summary": "A personal token was used",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Personal API tokens can't be used for admin actions."
                    }
                  },
                  "network": {
                    "summary": "The admin IP allowlist doesn't include the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/license": {
      "get": {
        "operationId": "getLicenseStatus",
        "summary": "Get license status",
        "description": "Returns the license plan, whether it is valid, its seats and how many are used, and any grace period with what will change when it ends.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "token": [
              "system:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/LicenseStatus"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "tier": "Enterprise",
                    "valid": true,
                    "license_key": "A1B2…9Z8Y",
                    "max_users": 50,
                    "machine_id": "7d2e9c41-5a3b-4f6e-8c1d-2b4a6e8f0c13",
                    "fingerprint": "e4b1c9a2-7f3d-4a8e-9b6c-1d2f3a4b5c6d",
                    "activated": true,
                    "trial": false,
                    "validation_error": "",
                    "needs_activation": false,
                    "active_users": 42,
                    "pending_invites": 3,
                    "effective_users": 45,
                    "domain_count": 2,
                    "max_domains": 0,
                    "last_validated": "2026-10-02T06:00:00Z",
                    "expires_at": "2027-09-30T00:00:00Z"
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid; `message` says what to change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "actAs": {
                    "summary": "A Dew-Act-As header was sent",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Dew-Act-As can't be used for admin actions."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, is a personal token, or the caller's network is not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scopeMissing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "personalToken": {
                    "summary": "A personal token was used",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Personal API tokens can't be used for admin actions."
                    }
                  },
                  "network": {
                    "summary": "The admin IP allowlist doesn't include the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/notifications": {
      "get": {
        "operationId": "listAdminNotifications",
        "summary": "List admin alerts",
        "description": "Returns the alerts admins see under the bell that nobody has dismissed yet, newest first: certificates and license expiring, storage running out or unreachable, email delivery problems, API tokens expiring and new versions.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "token": [
              "system:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            },
            "description": "Most alerts to return. Values outside 1 to 200 return 50."
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/AdminNotification"
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "5e8a1c3d-9b2f-4e7a-8c6d-0f1e2d3c4b5a",
                      "category": "cert_expiry",
                      "severity": "warn",
                      "title": "Certificate expires soon",
                      "message": "The certificate for files.example.com expires in 7 days.",
                      "dismissed": false,
                      "created_at": "2026-10-02T06:00:04Z"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid; `message` says what to change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "actAs": {
                    "summary": "A Dew-Act-As header was sent",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Dew-Act-As can't be used for admin actions."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, is a personal token, or the caller's network is not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scopeMissing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "personalToken": {
                    "summary": "A personal token was used",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Personal API tokens can't be used for admin actions."
                    }
                  },
                  "network": {
                    "summary": "The admin IP allowlist doesn't include the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/notifications/count": {
      "get": {
        "operationId": "countAdminNotifications",
        "summary": "Count admin alerts",
        "description": "Returns how many alerts nobody has dismissed yet, and the most severe of them.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "token": [
              "system:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Success"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "required": [
                            "count",
                            "severity"
                          ],
                          "properties": {
                            "count": {
                              "type": "integer"
                            },
                            "severity": {
                              "type": "string",
                              "enum": [
                                "error",
                                "warn",
                                ""
                              ],
                              "description": "The most severe undismissed alert: `error`, `warn`, or empty when there is none."
                            }
                          }
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "success": true,
                  "data": {
                    "count": 2,
                    "severity": "warn"
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid; `message` says what to change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "actAs": {
                    "summary": "A Dew-Act-As header was sent",
                    "value": {
                      "success": false,
                      "error": "Bad Request",
                      "message": "Dew-Act-As can't be used for admin actions."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token lacks the permission, is a personal token, or the caller's network is not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "scopeMissing": {
                    "summary": "The token lacks the permission",
                    "value": {
                      "success": false,
                      "error": "ScopeMissing",
                      "message": "This API token doesn't have permission for this action."
                    }
                  },
                  "personalToken": {
                    "summary": "A personal token was used",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Personal API tokens can't be used for admin actions."
                    }
                  },
                  "network": {
                    "summary": "The admin IP allowlist doesn't include the caller",
                    "value": {
                      "success": false,
                      "error": "Forbidden",
                      "message": "Admin access is not allowed from this network."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    }
  }
}
