{
  "openapi": "3.1.0",
  "info": {
    "title": "Revdoku API",
    "version": "2.0.0",
    "description": "Buckets with an email address, private files and a site. Create buckets, read and reply to email, store files and publish sites. Guide: https://docs.revdoku.com/api/. Create an account at https://app.revdoku.com/users/sign_up."
  },
  "servers": [
    {
      "url": "https://api.revdoku.com",
      "description": "Revdoku application API"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Authentication",
      "description": "Sign-in helpers for the CLI and AI agents. Backend applications use an API key from the dashboard."
    },
    {
      "name": "Accounts",
      "description": "Connection status, granted accounts and limits."
    },
    {
      "name": "Buckets",
      "description": "Create, read, archive and delete buckets."
    },
    {
      "name": "Tickets",
      "description": "Support tickets: each conversation that someone started with the bucket, by email, a message left on the docs site or page feedback. Read them, reply to the requester, solve and label them."
    },
    {
      "name": "Events",
      "description": "Ticket events of every channel: one signed webhook per bucket and live WebSocket subscriptions."
    },
    {
      "name": "Files",
      "description": "Upload, read, organize and restore files."
    },
    {
      "name": "Publications",
      "description": "A bucket's site: publish its files, preview them for 24 hours, or take the site down."
    },
    {
      "name": "GitHub",
      "description": "Connect a GitHub repository to a bucket: its files become a copy of one branch, and each push updates them."
    }
  ],
  "paths": {
    "/v1/auth/sign_in_code": {
      "post": {
        "operationId": "requestSignInCode",
        "tags": [
          "Authentication"
        ],
        "summary": "Email a sign-in code",
        "description": "Sends a six-digit code to an existing account email. The response is the same for every address, so it never reveals whether an account exists. Create new accounts in the browser at https://app.revdoku.com/users/sign_up.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "account_id": {
                    "type": "string",
                    "description": "Select another granted account for this request."
                  },
                  "reason": {
                    "$ref": "#/components/schemas/ActionReason"
                  }
                },
                "required": [
                  "email"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/CodeRequested"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/auth/sign_in_code/verify": {
      "post": {
        "operationId": "verifySignInCode",
        "tags": [
          "Authentication"
        ],
        "summary": "Exchange a sign-in code for an API key",
        "description": "Creates an AI agent connection for an account owner or administrator. Accounts with two-factor authentication must use browser sign-in.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "code": {
                    "type": "string",
                    "description": "Six digits; spaces are ignored."
                  },
                  "label": {
                    "type": "string",
                    "description": "Connection name shown in Account access."
                  },
                  "permission_scope": {
                    "type": "string",
                    "enum": [
                      "bucket_read",
                      "bucket_write",
                      "bucket_admin"
                    ],
                    "default": "bucket_admin"
                  },
                  "bucket_access": {
                    "type": "string",
                    "enum": [
                      "all",
                      "selected"
                    ],
                    "default": "all"
                  },
                  "bucket_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Required when bucket_access is selected."
                  },
                  "bucket_permissions": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "string",
                      "enum": [
                        "read",
                        "write"
                      ]
                    },
                    "description": "Optional access per selected bucket ID: read or write. Without an entry, a bucket gets write, or read when permission_scope is bucket_read."
                  },
                  "account_id": {
                    "type": "string",
                    "description": "Select another granted account for this request."
                  },
                  "reason": {
                    "$ref": "#/components/schemas/ActionReason"
                  }
                },
                "required": [
                  "email",
                  "code"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/AgentConnection"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/auth/grant/exchange": {
      "post": {
        "operationId": "exchangeConnectionGrant",
        "tags": [
          "Authentication"
        ],
        "summary": "Exchange a one-time dashboard connection code for an API key",
        "description": "The dashboard creates the one-time code when a signed-in administrator copies a connection prompt.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "grant_token": {
                    "type": "string"
                  },
                  "label": {
                    "type": "string"
                  },
                  "account_id": {
                    "type": "string",
                    "description": "Select another granted account for this request."
                  },
                  "reason": {
                    "$ref": "#/components/schemas/ActionReason"
                  }
                },
                "required": [
                  "grant_token"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/AgentConnection"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/auth/dashboard_link": {
      "post": {
        "operationId": "createDashboardLink",
        "tags": [
          "Authentication"
        ],
        "summary": "Create a dashboard link",
        "description": "Returns a dashboard URL for a path such as /buckets. The user signs in normally; the link grants no access.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "redirect_path": {
                    "type": "string",
                    "default": "/buckets"
                  },
                  "account_id": {
                    "type": "string",
                    "description": "Select another granted account for this request."
                  },
                  "reason": {
                    "$ref": "#/components/schemas/ActionReason"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/BrowserLink"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/status": {
      "get": {
        "operationId": "getStatus",
        "tags": [
          "Accounts"
        ],
        "summary": "Read the connection and selected account",
        "description": "Works with every API key, including bucket-scoped keys. Read quotas with GET /v1/account/limits.",
        "parameters": [
          {
            "$ref": "#/components/parameters/AccountId"
          },
          {
            "$ref": "#/components/parameters/Reason"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Status"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "connected": true,
                    "default_account_id": "acct_example",
                    "accounts": [
                      {
                        "id": "acct_example",
                        "name": "Acme",
                        "account_kind": "standard",
                        "client_name": null,
                        "agency_account": null
                      }
                    ],
                    "server_version": "1.0.575",
                    "client_version": "1.0.575",
                    "features": {
                      "email_domains": true
                    },
                    "account": {
                      "id": "acct_example",
                      "name": "Acme",
                      "status": "active",
                      "account_kind": "standard",
                      "client_name": null,
                      "agency_account": null,
                      "can_create_client_account": false,
                      "can_manage_billing": true,
                      "billing_message": null,
                      "previous_status": null,
                      "status_reason": null,
                      "status_updated_at": null
                    },
                    "user": {
                      "id": "user_example",
                      "email": "ada@example.com",
                      "name": "Ada Lovelace"
                    },
                    "dashboard_url": "https://app.revdoku.com/buckets?account_id=acct_example",
                    "connection": {
                      "api_key_id": "atok_example",
                      "label": "Orders backend",
                      "token_type": "api",
                      "scope": "bucket_admin",
                      "expires_at": "2027-10-11T12:00:00Z",
                      "last_used_at": "2026-10-11T12:20:00Z",
                      "bucket_access": "all",
                      "bucket_ids": [],
                      "denied_bucket_ids": [],
                      "bucket_permissions": {},
                      "permissions": {
                        "read": true,
                        "write": true,
                        "admin": true
                      },
                      "agent": null,
                      "transport": "api_key",
                      "renewal": {
                        "recommended": false
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/accounts": {
      "get": {
        "operationId": "listAccounts",
        "tags": [
          "Accounts"
        ],
        "summary": "List accounts granted to this credential",
        "description": "Works with every API key. Lists the account of this credential and the client accounts that an agency owner granted to it. Send an id from this list as account_id to act in that account.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/AccountList"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "default_account_id": "acct_example",
                    "accounts": [
                      {
                        "id": "acct_example",
                        "name": "Acme",
                        "account_kind": "standard",
                        "client_name": null,
                        "agency_account": null,
                        "region": "eu",
                        "status": "active",
                        "permissions": {
                          "scope": "bucket_admin",
                          "bucket_access": "all",
                          "can_create_buckets": true
                        }
                      }
                    ],
                    "pagination": {
                      "limit": 50,
                      "has_more": false,
                      "next_cursor": null
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "operationId": "createClientAccount",
        "tags": [
          "Accounts"
        ],
        "summary": "Create a client account",
        "description": "Requires an agency owner credential with client-account access. The credential default does not change; send the new account_id on later requests.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1
                  },
                  "client_name": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "Optional client person or business name."
                  },
                  "account_id": {
                    "type": "string",
                    "description": "Granted agency account that owns the new client account."
                  },
                  "reason": {
                    "$ref": "#/components/schemas/ActionReason"
                  }
                },
                "required": [
                  "name"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "account"
                      ],
                      "properties": {
                        "account": {
                          "$ref": "#/components/schemas/AccountIdentity"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/accounts/{account_id}": {
      "get": {
        "operationId": "getAccount",
        "tags": [
          "Accounts"
        ],
        "summary": "Read one granted account",
        "description": "Works with every API key. Returns the name, kind, region and status of one account that this credential can use, and the permissions of the credential in it. Other account IDs return 403.",
        "parameters": [
          {
            "$ref": "#/components/parameters/AccountPathId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "account"
                      ],
                      "properties": {
                        "account": {
                          "$ref": "#/components/schemas/AccountIdentity"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "account": {
                      "id": "acct_example",
                      "name": "Acme",
                      "account_kind": "standard",
                      "client_name": null,
                      "agency_account": null,
                      "region": "eu",
                      "status": "active",
                      "permissions": {
                        "scope": "bucket_admin",
                        "bucket_access": "all",
                        "can_create_buckets": true
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/account/limits": {
      "get": {
        "operationId": "getAccountLimits",
        "tags": [
          "Accounts"
        ],
        "summary": "Read effective account limits",
        "description": "Values come from the plan and account overrides. Zero means no allowance; null means no cap. Storage, bucket and email traffic allowances are shared within a billing group.",
        "parameters": [
          {
            "$ref": "#/components/parameters/AccountId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "account_id",
                        "limits"
                      ],
                      "properties": {
                        "account_id": {
                          "type": "string"
                        },
                        "limits": {
                          "$ref": "#/components/schemas/AccountLimits"
                        },
                        "usage": {
                          "type": "object",
                          "properties": {
                            "bucket_creations": {
                              "type": "object",
                              "properties": {
                                "monthly_limit": {
                                  "type": [
                                    "integer",
                                    "null"
                                  ]
                                },
                                "used": {
                                  "type": "integer"
                                },
                                "remaining": {
                                  "type": [
                                    "integer",
                                    "null"
                                  ]
                                },
                                "resets_at": {
                                  "type": "string",
                                  "format": "date-time"
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "account_id": "acct_example",
                    "limits": {
                      "max_buckets": 3,
                      "max_bucket_creations_per_month": 12,
                      "max_files_per_bucket": 25000,
                      "max_current_files": 40000,
                      "max_storage_bytes": 2147483648,
                      "max_file_size_bytes": 52428800,
                      "max_pdf_size_bytes": 52428800,
                      "max_file_versions_per_file": 15,
                      "max_email_aliases_per_bucket": 4,
                      "max_email_domains": 3,
                      "max_received_emails_per_month": 1500,
                      "max_received_email_bytes_per_month": 268435456,
                      "max_received_email_message_bytes": 20971520,
                      "max_sent_emails_per_month": 750,
                      "max_email_address_rotations_per_month": 6,
                      "max_account_members": 3,
                      "max_api_keys": 4,
                      "max_agent_connections": 7,
                      "api_rate_limit_requests_per_minute": 240,
                      "audit_retention_days": 45
                    },
                    "usage": {
                      "bucket_creations": {
                        "monthly_limit": 12,
                        "used": 2,
                        "remaining": 10,
                        "resets_at": "2026-11-01T00:00:00Z"
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets": {
      "get": {
        "operationId": "listBuckets",
        "tags": [
          "Buckets"
        ],
        "summary": "List buckets",
        "description": "Lists active buckets by default, newest first. Counts and pages cover only buckets this credential can access. Reads no email content.",
        "parameters": [
          {
            "$ref": "#/components/parameters/AccountId"
          },
          {
            "$ref": "#/components/parameters/Reason"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "archived",
                "all"
              ],
              "default": "active"
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "description": "Case-insensitive text in the bucket ID, or in the title or address when the key can see the address."
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/BucketList"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "buckets": [
                      {
                        "id": "bkt_example",
                        "account_id": "acct_example",
                        "title": "acme-orders",
                        "description": null,
                        "metadata": {},
                        "metadata_version": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
                        "email": {
                          "address": "acme-orders@revdokumail.com",
                          "message_count": 1,
                          "unread_count": 1,
                          "last_received_at": "2026-10-11T12:05:00.000000Z",
                          "receiving_enabled": true,
                          "sending_enabled": true
                        },
                        "archived": false,
                        "archived_at": null,
                        "lock": {
                          "locked": false
                        },
                        "storage_bytes": 51840,
                        "files_count": 3,
                        "version_id": "bktrv_example",
                        "version_number": 0,
                        "created_at": "2026-10-11T12:00:00.000000Z",
                        "updated_at": "2026-10-11T12:05:00.000000Z",
                        "dashboard_url": "https://app.revdoku.com/buckets/view?account_id=acct_example&id=bkt_example",
                        "archive": {
                          "allowed": true
                        },
                        "unarchive": {
                          "allowed": false,
                          "blocked_reason": "not_archived"
                        },
                        "delete": {
                          "allowed": false,
                          "blocked_reason": "not_archived",
                          "required_action": "archive_first",
                          "confirmation": "delete bkt_example"
                        }
                      }
                    ],
                    "counts": {
                      "active": 1,
                      "archived": 0,
                      "total": 1
                    },
                    "pagination": {
                      "limit": 50,
                      "has_more": false,
                      "next_cursor": null
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "operationId": "createBucket",
        "tags": [
          "Buckets"
        ],
        "summary": "Create a bucket",
        "description": "Waits until the address can receive email. On revdokumail.com, email.username is the bucket's name, with no suffix: lowercase letters, digits and single hyphens, 3 to 63 characters, also the name of its site. A name that another bucket uses as an address or a site address, or that another account used, returns EMAIL_ALREADY_EXISTS; your account can use its own earlier names again. Without email.username the address takes the title's name when it is free, else two readable words. A custom domain takes the exact name. If confirmation does not finish, EMAIL_NOT_READY returns the created bucket_id in error.details: read that bucket instead of creating another. The title defaults to email.username; a title that another active bucket uses returns 409 BUCKET_TITLE_TAKEN. Never retry a creation automatically.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "bucket": {
                    "$ref": "#/components/schemas/BucketCreate"
                  },
                  "account_id": {
                    "type": "string",
                    "description": "Select another granted account for this request."
                  },
                  "reason": {
                    "$ref": "#/components/schemas/ActionReason"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "bucket"
                      ],
                      "properties": {
                        "bucket": {
                          "$ref": "#/components/schemas/Bucket"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "bucket": {
                      "id": "bkt_example",
                      "account_id": "acct_example",
                      "title": "acme-orders",
                      "description": null,
                      "metadata": {},
                      "metadata_version": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
                      "email": {
                        "address": "acme-orders@revdokumail.com",
                        "message_count": 0,
                        "unread_count": 0,
                        "last_received_at": null,
                        "receiving_enabled": true,
                        "sending_enabled": true
                      },
                      "archived": false,
                      "archived_at": null,
                      "lock": {
                        "locked": false
                      },
                      "storage_bytes": 0,
                      "files_count": 0,
                      "version_id": "bktrv_example",
                      "version_number": 0,
                      "created_at": "2026-10-11T12:00:00.000000Z",
                      "updated_at": "2026-10-11T12:00:00.000000Z",
                      "dashboard_url": "https://app.revdoku.com/buckets/view?account_id=acct_example&id=bkt_example",
                      "archive": {
                        "allowed": true
                      },
                      "unarchive": {
                        "allowed": false,
                        "blocked_reason": "not_archived"
                      },
                      "delete": {
                        "allowed": false,
                        "blocked_reason": "not_archived",
                        "required_action": "archive_first",
                        "confirmation": "delete bkt_example"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "UNAUTHORIZED",
                    "message": "Authentication required",
                    "request_id": "req_example"
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}": {
      "get": {
        "operationId": "getBucket",
        "tags": [
          "Buckets"
        ],
        "summary": "Read a bucket",
        "description": "Reading never changes the bucket. Read address settings, emails and files through their own endpoints.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/AccountId"
          },
          {
            "$ref": "#/components/parameters/Reason"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "bucket"
                      ],
                      "properties": {
                        "bucket": {
                          "$ref": "#/components/schemas/Bucket"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "bucket": {
                      "id": "bkt_example",
                      "account_id": "acct_example",
                      "title": "acme-orders",
                      "description": null,
                      "metadata": {},
                      "metadata_version": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
                      "email": {
                        "address": "acme-orders@revdokumail.com",
                        "message_count": 1,
                        "unread_count": 1,
                        "last_received_at": "2026-10-11T12:05:00.000000Z",
                        "receiving_enabled": true,
                        "sending_enabled": true
                      },
                      "archived": false,
                      "archived_at": null,
                      "lock": {
                        "locked": false
                      },
                      "storage_bytes": 51840,
                      "files_count": 3,
                      "version_id": "bktrv_example",
                      "version_number": 0,
                      "created_at": "2026-10-11T12:00:00.000000Z",
                      "updated_at": "2026-10-11T12:05:00.000000Z",
                      "dashboard_url": "https://app.revdoku.com/buckets/view?account_id=acct_example&id=bkt_example",
                      "archive": {
                        "allowed": true
                      },
                      "unarchive": {
                        "allowed": false,
                        "blocked_reason": "not_archived"
                      },
                      "delete": {
                        "allowed": false,
                        "blocked_reason": "not_archived",
                        "required_action": "archive_first",
                        "confirmation": "delete bkt_example"
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "patch": {
        "operationId": "updateBucket",
        "tags": [
          "Buckets"
        ],
        "summary": "Update a bucket title, description or metadata",
        "description": "metadata must be a JSON object. It replaces the stored object; {} clears it. Send expected_metadata_version from your last read; a stale value changes nothing and returns BUCKET_METADATA_CONFLICT. Titles are unique among active buckets; a used title returns 409 BUCKET_TITLE_TAKEN.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "bucket": {
                    "$ref": "#/components/schemas/BucketUpdate"
                  },
                  "expected_metadata_version": {
                    "type": "string"
                  },
                  "account_id": {
                    "type": "string",
                    "description": "Select another granted account for this request."
                  },
                  "reason": {
                    "$ref": "#/components/schemas/ActionReason"
                  }
                },
                "required": [
                  "bucket"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "bucket"
                      ],
                      "properties": {
                        "bucket": {
                          "$ref": "#/components/schemas/Bucket"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "operationId": "deleteBucket",
        "tags": [
          "Buckets"
        ],
        "summary": "Permanently delete an archived bucket",
        "description": "Archive the bucket first. Send delete.confirmation from the bucket read after the user confirms. Large buckets finish deleting in the background.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "confirmation": {
                    "type": "string"
                  },
                  "account_id": {
                    "type": "string",
                    "description": "Select another granted account for this request."
                  },
                  "reason": {
                    "$ref": "#/components/schemas/ActionReason"
                  }
                },
                "required": [
                  "confirmation"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/DeleteResult"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/archive": {
      "post": {
        "operationId": "archiveBucket",
        "tags": [
          "Buckets"
        ],
        "summary": "Archive a bucket",
        "description": "Archived buckets keep their files and emails and become read-only.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ActionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "bucket"
                      ],
                      "properties": {
                        "bucket": {
                          "$ref": "#/components/schemas/Bucket"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/unarchive": {
      "post": {
        "operationId": "unarchiveBucket",
        "tags": [
          "Buckets"
        ],
        "summary": "Unarchive a bucket",
        "description": "Requires bucket-admin permission. The bucket becomes writable again. If another active bucket has the same title, the title gets a number suffix. A bucket that is not archived returns BUCKET_NOT_ARCHIVED.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ActionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "bucket"
                      ],
                      "properties": {
                        "bucket": {
                          "$ref": "#/components/schemas/Bucket"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/lock": {
      "post": {
        "operationId": "lockBucket",
        "tags": [
          "Buckets"
        ],
        "summary": "Lock a bucket or some of its files",
        "description": "Tells other people and agents to wait while you edit. Without paths it locks the whole bucket and requires bucket-admin permission; with paths it locks those files and requires write permission. Others get 423 BUCKET_LOCKED or FILE_LOCKED until you unlock or the lock expires. A lock of someone else also returns 423. Locks never block incoming email. A batch upload (upload_sessions) locks the bucket by itself until it finishes. The MCP tool bucket_lock has the same contract.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LockRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/LockResult"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/unlock": {
      "post": {
        "operationId": "unlockBucket",
        "tags": [
          "Buckets"
        ],
        "summary": "Remove your lock",
        "description": "Removes your lock of the whole bucket (bucket-admin permission) or of the listed files (write permission). A lock of someone else, a running batch upload or a deletion returns 423 BUCKET_LOCKED or FILE_LOCKED. Unlocking an unlocked bucket returns its lock state.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UnlockRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/LockResult"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/webhook": {
      "get": {
        "operationId": "getWebhook",
        "tags": [
          "Events"
        ],
        "summary": "Read the webhook",
        "description": "Requires bucket-admin permission. webhook is null when no webhook is set. The signing secret is never returned here.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/AccountId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "webhook"
                      ],
                      "properties": {
                        "webhook": {
                          "anyOf": [
                            {
                              "$ref": "#/components/schemas/Webhook"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "put": {
        "operationId": "setWebhook",
        "tags": [
          "Events"
        ],
        "summary": "Set the webhook",
        "description": "Requires bucket-admin permission and a public HTTPS URL. The webhook receives the bucket's ticket events (TicketEvent): ticket.created and ticket.message_received, for every channel. A new URL or rotate_secret=true creates a new signing secret, returns it once and cancels pending deliveries. The same URL without rotate_secret returns the webhook without a secret.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "webhook_url": {
                    "type": "string",
                    "format": "uri",
                    "maxLength": 2048
                  },
                  "rotate_secret": {
                    "type": "boolean",
                    "default": false
                  },
                  "account_id": {
                    "type": "string",
                    "description": "Select another granted account for this request."
                  },
                  "reason": {
                    "$ref": "#/components/schemas/ActionReason"
                  }
                },
                "required": [
                  "webhook_url"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "webhook"
                      ],
                      "properties": {
                        "webhook": {
                          "$ref": "#/components/schemas/WebhookWithSecret"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "operationId": "deleteWebhook",
        "tags": [
          "Events"
        ],
        "summary": "Remove the webhook",
        "description": "Cancels queued deliveries. A delivery already in progress can finish. Returns the bucket ID, also when no webhook is set.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/AccountId"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/DeleteResult"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/events/subscription": {
      "get": {
        "operationId": "getEventSubscription",
        "tags": [
          "Events"
        ],
        "summary": "Get a live event subscription ticket",
        "description": "Requires bucket read permission. Connect to websocket_url with subscription_token=TOKEN within 60 seconds, then subscribe to BucketEventsChannel with account_id and bucket_id. Each event is a TicketEvent. Catch up with GET /v1/buckets/{bucket_id}/tickets and updated_after after every connect.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/AccountId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "subscription"
                      ],
                      "properties": {
                        "subscription": {
                          "$ref": "#/components/schemas/EventSubscription"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/tickets": {
      "get": {
        "operationId": "listTickets",
        "tags": [
          "Tickets"
        ],
        "summary": "List tickets",
        "description": "Lists the bucket's support tickets, newest activity first. A ticket is one conversation that someone started: an email, a message left on the docs site, or anonymous page feedback. Tickets whose first message AI labels marked as Junk are left out unless label is Junk. To poll, pass the newest updated_at you have seen as updated_after. Reads no message content.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/AccountId"
          },
          {
            "$ref": "#/components/parameters/Reason"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "solved",
                "all"
              ],
              "default": "all"
            },
            "description": "Ticket status."
          },
          {
            "name": "channel",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "email",
                "chat",
                "feedback"
              ]
            },
            "description": "Only tickets that started in this channel."
          },
          {
            "name": "label",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Only tickets with a message that has this label, such as Junk."
          },
          {
            "name": "updated_after",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only tickets with activity after this ISO 8601 time."
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/TicketList"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "tickets": [
                      {
                        "id": "tkt_example",
                        "number": 3,
                        "status": "open",
                        "subject": "How do I rotate my API key?",
                        "channel": "email",
                        "requester": {
                          "address": "dev@example.com",
                          "name": "Dana Developer"
                        },
                        "labels": [],
                        "message_count": 2,
                        "unread_count": 1,
                        "created_at": "2026-10-11T12:05:00.000000Z",
                        "updated_at": "2026-10-11T12:30:00.000000Z",
                        "last_message_at": "2026-10-11T12:30:00.000000Z",
                        "solved_at": null
                      }
                    ],
                    "pagination": {
                      "limit": 50,
                      "has_more": false,
                      "next_cursor": null
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/tickets/{ticket_id}": {
      "get": {
        "operationId": "getTicket",
        "tags": [
          "Tickets"
        ],
        "summary": "Read a ticket",
        "description": "Returns the ticket without its messages. List them with GET /v1/buckets/{bucket_id}/tickets/{ticket_id}/messages.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/TicketId"
          },
          {
            "$ref": "#/components/parameters/AccountId"
          },
          {
            "$ref": "#/components/parameters/Reason"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "ticket"
                      ],
                      "properties": {
                        "ticket": {
                          "$ref": "#/components/schemas/Ticket"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "ticket": {
                      "id": "tkt_example",
                      "number": 3,
                      "status": "open",
                      "subject": "How do I rotate my API key?",
                      "channel": "email",
                      "requester": {
                        "address": "dev@example.com",
                        "name": "Dana Developer"
                      },
                      "labels": [],
                      "message_count": 2,
                      "unread_count": 1,
                      "created_at": "2026-10-11T12:05:00.000000Z",
                      "updated_at": "2026-10-11T12:30:00.000000Z",
                      "last_message_at": "2026-10-11T12:30:00.000000Z",
                      "solved_at": null
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "patch": {
        "operationId": "updateTicket",
        "tags": [
          "Tickets"
        ],
        "summary": "Solve, reopen or label a ticket",
        "description": "Requires bucket write permission. status solved or open changes every ticket of a merged conversation. add_labels labels the first message; remove_labels removes the labels from every message. Built-in labels such as Junk change only in the dashboard. While an agent works on a message, a label change returns 423 EMAIL_LOCKED.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/TicketId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TicketUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "ticket"
                      ],
                      "properties": {
                        "ticket": {
                          "$ref": "#/components/schemas/Ticket"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/tickets/{ticket_id}/messages": {
      "get": {
        "operationId": "listTicketMessages",
        "tags": [
          "Tickets"
        ],
        "summary": "List the messages of a ticket",
        "description": "Lists the ticket's messages oldest first, with body_text and attachment metadata. Does not change read status. Junk email and new email that AI labels still check are withheld: body_status is withheld.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/TicketId"
          },
          {
            "$ref": "#/components/parameters/AccountId"
          },
          {
            "$ref": "#/components/parameters/Reason"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 20
            },
            "description": "Page size, 1 to 50."
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/IncludeStorage"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/TicketMessageList"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "operationId": "replyToTicket",
        "tags": [
          "Tickets"
        ],
        "summary": "Reply to the requester",
        "description": "Requires bucket write permission. Revdoku sends only replies: the reply goes to the ticket's requester, the verified sender of its newest received message. A ticket without one, such as anonymous feedback, returns 403 EMAIL_RECIPIENT_NOT_ALLOWED. When the bucket requires approval, delivery.status is awaiting_approval until a person sends, edits or declines the reply; do not send it again. A reply to Junk email returns 403 EMAIL_WITHHELD; one that AI labels are still checking returns 503 EMAIL_LABELING_PENDING with Retry-After. The subject ends with [#number]. On the Free plan, the email ends with one line about Revdoku. Delivery is asynchronous. After an unknown result, read the ticket before you send again. Uses credits; see https://app.revdoku.com/pricing.json.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/TicketId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TicketReplyRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "message"
                      ],
                      "properties": {
                        "message": {
                          "$ref": "#/components/schemas/TicketMessage"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/tickets/{ticket_id}/messages/{message_id}": {
      "get": {
        "operationId": "getTicketMessage",
        "tags": [
          "Tickets"
        ],
        "summary": "Read a message",
        "description": "Returns one message with body_text and attachment metadata. Does not change read status. A new email that AI labels still check returns 503 EMAIL_LABELING_PENDING with Retry-After.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/TicketId"
          },
          {
            "$ref": "#/components/parameters/MessageId"
          },
          {
            "$ref": "#/components/parameters/AccountId"
          },
          {
            "$ref": "#/components/parameters/Reason"
          },
          {
            "$ref": "#/components/parameters/IncludeStorage"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "message"
                      ],
                      "properties": {
                        "message": {
                          "$ref": "#/components/schemas/TicketMessage"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "message": {
                      "id": "eml_example",
                      "conversation_id": "eml_example",
                      "direction": "received",
                      "subject": "Invoice INV-1042",
                      "from_addresses": [
                        {
                          "address": "billing@example.com",
                          "name": "Example Billing"
                        }
                      ],
                      "to_addresses": [
                        {
                          "address": "acme-orders@revdokumail.com",
                          "name": null
                        }
                      ],
                      "cc_addresses": [],
                      "reply_to_addresses": [],
                      "message_id": "inv-1042@example.com",
                      "in_reply_to": [],
                      "references": [],
                      "delivered_to": "acme-orders@revdokumail.com",
                      "received_at": "2026-10-11T12:05:00.000000Z",
                      "body_status": "complete",
                      "attachment_count": 1,
                      "labels": [
                        {
                          "id": "tag_example",
                          "name": "Receipts",
                          "color": "yellow"
                        }
                      ],
                      "withheld": false,
                      "read": false,
                      "read_at": null,
                      "read_by": null,
                      "read_by_api_key": null,
                      "body_text": "Hello,\n\nInvoice INV-1042 for October is attached.\n\nExample Billing",
                      "attachments": [
                        {
                          "id": "df_example",
                          "filename": "INV-1042.pdf",
                          "content_type": "application/pdf",
                          "size_bytes": 48213
                        }
                      ],
                      "ticket_id": "tkt_example",
                      "channel": "email"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "operationId": "deleteTicketMessage",
        "tags": [
          "Tickets"
        ],
        "summary": "Delete a message",
        "description": "Requires bucket-admin permission. Deletes one message with its files and attachments.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/TicketId"
          },
          {
            "$ref": "#/components/parameters/MessageId"
          },
          {
            "$ref": "#/components/parameters/AccountId"
          },
          {
            "$ref": "#/components/parameters/Reason"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/DeleteResult"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "deleted": true,
                    "id": "eml_example"
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/tickets/{ticket_id}/messages/{message_id}/raw": {
      "get": {
        "operationId": "getTicketMessageOriginalDownload",
        "tags": [
          "Tickets"
        ],
        "summary": "Get a download link for the original email",
        "description": "Returns a temporary link to the original .eml file. Downloads do not change read status. Junk email returns 403 EMAIL_WITHHELD. A new email that AI labels are still checking returns 503 EMAIL_LABELING_PENDING with Retry-After.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/TicketId"
          },
          {
            "$ref": "#/components/parameters/MessageId"
          },
          {
            "$ref": "#/components/parameters/AccountId"
          },
          {
            "$ref": "#/components/parameters/Reason"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "download"
                      ],
                      "properties": {
                        "download": {
                          "$ref": "#/components/schemas/Download"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/tickets/{ticket_id}/messages/{message_id}/attachments/{attachment_id}": {
      "get": {
        "operationId": "getTicketMessageAttachmentDownload",
        "tags": [
          "Tickets"
        ],
        "summary": "Get a download link for an attachment",
        "description": "Returns a temporary link. No extraction or analysis is done. Junk email returns 403 EMAIL_WITHHELD. A new email that AI labels are still checking returns 503 EMAIL_LABELING_PENDING with Retry-After.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/TicketId"
          },
          {
            "$ref": "#/components/parameters/MessageId"
          },
          {
            "$ref": "#/components/parameters/AttachmentId"
          },
          {
            "$ref": "#/components/parameters/AccountId"
          },
          {
            "$ref": "#/components/parameters/Reason"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "download"
                      ],
                      "properties": {
                        "download": {
                          "$ref": "#/components/schemas/Download"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "download": {
                      "url": "https://storage.example/INV-1042.pdf?X-Amz-Expires=900&X-Amz-Signature=EXAMPLE",
                      "filename": "INV-1042.pdf",
                      "content_type": "application/pdf",
                      "size_bytes": 48213,
                      "expires_in": 900
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/files": {
      "get": {
        "operationId": "listFiles",
        "tags": [
          "Files"
        ],
        "summary": "List files",
        "description": "Lists current files, including stored emails under _mailbox/. Listing never marks files read.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/AccountId"
          },
          {
            "$ref": "#/components/parameters/Reason"
          },
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Case-insensitive text in the path."
          },
          {
            "name": "folder",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "List one folder. An empty value lists the root."
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/FileList"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "files": [
                      {
                        "id": "df_example",
                        "bucket_id": "bkt_example",
                        "basename": "summary.txt",
                        "path": "reports/summary.txt",
                        "role": "source",
                        "deleted": false,
                        "lock": {
                          "locked": false
                        },
                        "current_file_version": {
                          "id": "dfrev_example",
                          "file_id": "df_example",
                          "version_number": 0,
                          "name": "summary.txt",
                          "mime_type": "text/plain",
                          "byte_size": 1234,
                          "sha256": "0d6a3c2b8f5e41a7c9b2d4e6f8a1c3e5b7d9f1a3c5e7b9d1f3a5c7e9b1d3f5a7",
                          "deleted": false,
                          "ready": true,
                          "has_text": false,
                          "created_at": "2026-10-11T12:20:00Z",
                          "created_by": {
                            "id": "user_example",
                            "email": "ada@example.com",
                            "name": "Ada Lovelace"
                          },
                          "updated_by": {
                            "id": "user_example",
                            "email": "ada@example.com",
                            "name": "Ada Lovelace"
                          },
                          "created_by_api_key": {
                            "id": "atok_example",
                            "label": "Orders backend",
                            "token_type": "api"
                          },
                          "created_by_agent": {
                            "name": "Orders backend"
                          },
                          "updated_by_api_key": {
                            "id": "atok_example",
                            "label": "Orders backend",
                            "token_type": "api"
                          },
                          "updated_by_agent": {
                            "name": "Orders backend"
                          },
                          "read": false,
                          "read_at": null,
                          "read_by": null,
                          "read_by_api_key": null
                        },
                        "created_by": {
                          "id": "user_example",
                          "email": "ada@example.com",
                          "name": "Ada Lovelace"
                        },
                        "created_by_api_key": {
                          "id": "atok_example",
                          "label": "Orders backend",
                          "token_type": "api"
                        },
                        "created_by_agent": {
                          "name": "Orders backend"
                        },
                        "updated_by_api_key": {
                          "id": "atok_example",
                          "label": "Orders backend",
                          "token_type": "api"
                        },
                        "updated_by_agent": {
                          "name": "Orders backend"
                        },
                        "created_at": "2026-10-11T12:20:00Z",
                        "updated_at": "2026-10-11T12:20:00Z",
                        "read": false,
                        "read_at": null,
                        "read_by": null,
                        "read_by_api_key": null
                      }
                    ],
                    "pagination": {
                      "limit": 50,
                      "has_more": false,
                      "next_cursor": null
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "operationId": "saveUploadedFile",
        "tags": [
          "Files"
        ],
        "summary": "Save an uploaded file (step 3 of 3)",
        "description": "Saves the uploaded blob at path. An existing path gets a new version.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaveUploadedFileRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/SavedFile"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "file": {
                      "id": "df_example",
                      "bucket_id": "bkt_example",
                      "basename": "summary.txt",
                      "path": "reports/summary.txt",
                      "role": "source",
                      "deleted": false,
                      "version_reasons": [],
                      "lock": {
                        "locked": false
                      },
                      "current_file_version": {
                        "id": "dfrev_example",
                        "file_id": "df_example",
                        "version_number": 0,
                        "name": "summary.txt",
                        "mime_type": "text/plain",
                        "byte_size": 1234,
                        "sha256": "0d6a3c2b8f5e41a7c9b2d4e6f8a1c3e5b7d9f1a3c5e7b9d1f3a5c7e9b1d3f5a7",
                        "deleted": false,
                        "ready": true,
                        "has_text": false,
                        "created_at": "2026-10-11T12:20:00Z",
                        "created_by": {
                          "id": "user_example",
                          "email": "ada@example.com",
                          "name": "Ada Lovelace"
                        },
                        "updated_by": {
                          "id": "user_example",
                          "email": "ada@example.com",
                          "name": "Ada Lovelace"
                        },
                        "created_by_api_key": {
                          "id": "atok_example",
                          "label": "Orders backend",
                          "token_type": "api"
                        },
                        "created_by_agent": {
                          "name": "Orders backend"
                        },
                        "updated_by_api_key": {
                          "id": "atok_example",
                          "label": "Orders backend",
                          "token_type": "api"
                        },
                        "updated_by_agent": {
                          "name": "Orders backend"
                        },
                        "read": false,
                        "read_at": null,
                        "read_by": null,
                        "read_by_api_key": null
                      },
                      "created_by": {
                        "id": "user_example",
                        "email": "ada@example.com",
                        "name": "Ada Lovelace"
                      },
                      "created_by_api_key": {
                        "id": "atok_example",
                        "label": "Orders backend",
                        "token_type": "api"
                      },
                      "created_by_agent": {
                        "name": "Orders backend"
                      },
                      "updated_by_api_key": {
                        "id": "atok_example",
                        "label": "Orders backend",
                        "token_type": "api"
                      },
                      "updated_by_agent": {
                        "name": "Orders backend"
                      },
                      "created_at": "2026-10-11T12:20:00Z",
                      "updated_at": "2026-10-11T12:20:00Z",
                      "read": false,
                      "read_at": null,
                      "read_by": null,
                      "read_by_api_key": null
                    },
                    "version": {
                      "id": "dfrev_example",
                      "file_id": "df_example",
                      "version_number": 0,
                      "name": "summary.txt",
                      "mime_type": "text/plain",
                      "byte_size": 1234,
                      "sha256": "0d6a3c2b8f5e41a7c9b2d4e6f8a1c3e5b7d9f1a3c5e7b9d1f3a5c7e9b1d3f5a7",
                      "deleted": false,
                      "ready": true,
                      "has_text": false,
                      "created_at": "2026-10-11T12:20:00Z",
                      "created_by": {
                        "id": "user_example",
                        "email": "ada@example.com",
                        "name": "Ada Lovelace"
                      },
                      "updated_by": {
                        "id": "user_example",
                        "email": "ada@example.com",
                        "name": "Ada Lovelace"
                      },
                      "created_by_api_key": {
                        "id": "atok_example",
                        "label": "Orders backend",
                        "token_type": "api"
                      },
                      "created_by_agent": {
                        "name": "Orders backend"
                      },
                      "updated_by_api_key": {
                        "id": "atok_example",
                        "label": "Orders backend",
                        "token_type": "api"
                      },
                      "updated_by_agent": {
                        "name": "Orders backend"
                      },
                      "read": false,
                      "read_at": null,
                      "read_by": null,
                      "read_by_api_key": null
                    },
                    "created": true
                  }
                }
              }
            }
          },
          "200": {
            "description": "Existing file kept",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/SavedFile"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/files/by_path": {
      "get": {
        "operationId": "getFileByPath",
        "tags": [
          "Files"
        ],
        "summary": "Find a file by path",
        "description": "Returns file metadata only. Read content with the download endpoint. The disposition and content_url parameters return INVALID_ARGUMENT.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "name": "path",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/AccountId"
          },
          {
            "$ref": "#/components/parameters/Reason"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "file"
                      ],
                      "properties": {
                        "file": {
                          "$ref": "#/components/schemas/BucketFile"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/files/append_text": {
      "post": {
        "operationId": "appendText",
        "tags": [
          "Files"
        ],
        "summary": "Append text to a file",
        "description": "Appends UTF-8 text to an existing text file and creates a new version. A missing file returns BUCKET_FILE_NOT_FOUND.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "path": {
                    "type": "string"
                  },
                  "content": {
                    "type": "string"
                  },
                  "newline_before": {
                    "type": "boolean",
                    "default": true
                  },
                  "expected_bucket_version": {
                    "type": "string",
                    "description": "Bucket version_id from your last read."
                  },
                  "account_id": {
                    "type": "string",
                    "description": "Select another granted account for this request."
                  },
                  "reason": {
                    "$ref": "#/components/schemas/ActionReason"
                  }
                },
                "required": [
                  "path",
                  "content"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/AppendTextResult"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/files/{file_id}": {
      "get": {
        "operationId": "getFile",
        "tags": [
          "Files"
        ],
        "summary": "Read file metadata",
        "description": "Reading metadata never marks the file read.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/FileId"
          },
          {
            "$ref": "#/components/parameters/AccountId"
          },
          {
            "$ref": "#/components/parameters/Reason"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "file"
                      ],
                      "properties": {
                        "file": {
                          "$ref": "#/components/schemas/BucketFile"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "operationId": "deleteFile",
        "tags": [
          "Files"
        ],
        "summary": "Delete a file",
        "description": "Requires bucket-admin permission. Files under _mailbox/ return MAILBOX_PATH_READ_ONLY; delete the ticket message instead. Files under _agents/ and _revdoku/ return RESERVED_PATH.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/FileId"
          },
          {
            "$ref": "#/components/parameters/AccountId"
          },
          {
            "$ref": "#/components/parameters/Reason"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/DeleteResult"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/files/{file_id}/download": {
      "get": {
        "operationId": "getFileDownload",
        "tags": [
          "Files"
        ],
        "summary": "Get a download link for a file",
        "description": "Returns a temporary link and marks this version read. Send version_id for an older version.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/FileId"
          },
          {
            "name": "version_id",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/AccountId"
          },
          {
            "$ref": "#/components/parameters/Reason"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/FileDownload"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/files/{file_id}/rename": {
      "post": {
        "operationId": "renameFile",
        "tags": [
          "Files"
        ],
        "summary": "Rename or move a file in the same bucket",
        "description": "Changes the path without uploading the content again.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/FileId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "new_path": {
                    "type": "string"
                  },
                  "account_id": {
                    "type": "string",
                    "description": "Select another granted account for this request."
                  },
                  "reason": {
                    "$ref": "#/components/schemas/ActionReason"
                  }
                },
                "required": [
                  "new_path"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/PathOperationResult"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/files/{file_id}/move": {
      "post": {
        "operationId": "moveFile",
        "tags": [
          "Files"
        ],
        "summary": "Move a file",
        "description": "Works in the same bucket or into target_bucket_id. Content is not uploaded again. Send target_path for an exact path or target_folder to keep the name.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/FileId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "target_bucket_id": {
                    "type": "string"
                  },
                  "target_path": {
                    "type": "string"
                  },
                  "target_folder": {
                    "type": "string"
                  },
                  "account_id": {
                    "type": "string",
                    "description": "Select another granted account for this request."
                  },
                  "reason": {
                    "$ref": "#/components/schemas/ActionReason"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/PathOperationResult"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/files/{file_id}/copy": {
      "post": {
        "operationId": "copyFile",
        "tags": [
          "Files"
        ],
        "summary": "Copy a file",
        "description": "Works in the same bucket or into target_bucket_id. Content is not uploaded again. Send target_path for an exact path or target_folder to keep the name.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/FileId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "target_bucket_id": {
                    "type": "string"
                  },
                  "target_path": {
                    "type": "string"
                  },
                  "target_folder": {
                    "type": "string"
                  },
                  "account_id": {
                    "type": "string",
                    "description": "Select another granted account for this request."
                  },
                  "reason": {
                    "$ref": "#/components/schemas/ActionReason"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/PathOperationResult"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/files/{file_id}/versions": {
      "get": {
        "operationId": "listFileVersions",
        "tags": [
          "Files"
        ],
        "summary": "List file versions",
        "description": "Newest first.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/FileId"
          },
          {
            "$ref": "#/components/parameters/AccountId"
          },
          {
            "$ref": "#/components/parameters/Reason"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/FileVersionList"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/files/{file_id}/versions/{version_id}/restore": {
      "post": {
        "operationId": "restoreFileVersion",
        "tags": [
          "Files"
        ],
        "summary": "Restore a file version",
        "description": "Creates a new current version with the content of the selected version. History is kept. Requires a plan with version restore.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/FileId"
          },
          {
            "$ref": "#/components/parameters/VersionId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ActionRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/RestoredFileVersion"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/uploads": {
      "post": {
        "operationId": "prepareFileUpload",
        "tags": [
          "Files"
        ],
        "summary": "Prepare a file upload (step 1 of 3)",
        "description": "Returns a storage URL. Then PUT the bytes to direct_upload.url with exactly direct_upload.headers and no API key (step 2), and save the file with POST /v1/buckets/{bucket_id}/files (step 3). Identical content at the same path returns skipped=true and duplicate=true without an upload.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PrepareFileUploadRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/PreparedFileUpload"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "signed_id": "eyJfcmFpbHMi...",
                    "filename": "document_7a77539cbd6d02a5.txt",
                    "byte_size": 1234,
                    "checksum": "rL0Y20zC+Fzt72VPzMSk2A==",
                    "content_type": "text/plain",
                    "direct_upload": {
                      "url": "https://storage.example/upload",
                      "headers": {
                        "Content-Type": "text/plain",
                        "Content-MD5": "rL0Y20zC+Fzt72VPzMSk2A==",
                        "Content-Disposition": "inline; filename=\"document_7a77539cbd6d02a5.txt\"; filename*=UTF-8''document_7a77539cbd6d02a5.txt"
                      }
                    }
                  }
                }
              }
            }
          },
          "200": {
            "description": "Identical content; nothing to upload",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/PreparedFileUpload"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          }
        ]
      }
    },
    "/v1/buckets/{bucket_id}/upload_sessions": {
      "post": {
        "operationId": "createUploadSession",
        "tags": [
          "Files"
        ],
        "summary": "Start a batch upload",
        "description": "Starts an upload session for many files and returns storage targets for the first files. The session locks the bucket for other writers; incoming email still arrives. Send files in batches with POST .../uploads, PUT the bytes to each upload.url, save each batch with POST .../finalize_batch, then call POST .../finalize. Unsaved uploads are discarded when the session expires.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "files": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "$ref": "#/components/schemas/UploadSessionFile"
                    },
                    "description": "Optional first batch. Send the rest with POST .../uploads."
                  },
                  "expected_file_count": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "Total files you will upload in this session. Used for progress."
                  },
                  "client_session_key": {
                    "type": "string",
                    "maxLength": 128,
                    "description": "Your own key for this batch. Repeating it with the same credential while the session is pending returns that session instead of a new one."
                  },
                  "existing_file_policy": {
                    "type": "string",
                    "enum": [
                      "replace",
                      "skip"
                    ],
                    "default": "replace",
                    "description": "skip keeps existing files at the same paths."
                  },
                  "expected_bucket_version": {
                    "type": "string",
                    "description": "Bucket version_id from your last read. A different current version returns BUCKET_VERSION_CONFLICT."
                  },
                  "account_id": {
                    "type": "string",
                    "description": "Select another granted account for this request."
                  },
                  "reason": {
                    "$ref": "#/components/schemas/ActionReason"
                  }
                }
              },
              "example": {
                "expected_file_count": 2,
                "client_session_key": "backup-2026-10-11",
                "files": [
                  {
                    "path": "reports/q3.pdf",
                    "byte_size": 48213,
                    "content_type": "application/pdf",
                    "checksum": "rL0Y20zC+Fzt72VPzMSk2A==",
                    "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/UploadSessionResult"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "bucket_upload_session": {
                      "id": "bus_example",
                      "bucket_id": "bkt_example",
                      "status": "pending",
                      "base_bucket_version_id": "bktrv_example",
                      "target_bucket_version_id": null,
                      "uploads_expire_at": "2026-10-11T14:00:00Z",
                      "session_closed_at": null,
                      "files_count": 2,
                      "pending_files_count": 2,
                      "uploaded_files_count": 0,
                      "finalized_files_count": 0,
                      "skipped_files_count": 0,
                      "skipped_code_counts": {},
                      "failed_files_count": 0
                    },
                    "uploads": [
                      {
                        "input_index": 0,
                        "path": "reports/q3.pdf",
                        "name": "q3.pdf",
                        "signed_blob_id": "eyJfcmFpbHMi...",
                        "upload": {
                          "url": "https://storage.example/upload",
                          "headers": {
                            "Content-Type": "application/pdf",
                            "Content-MD5": "rL0Y20zC+Fzt72VPzMSk2A=="
                          }
                        }
                      }
                    ],
                    "uploaded": [],
                    "uploaded_count": 0,
                    "uploaded_truncated": false,
                    "created_count": 0,
                    "updated_count": 0,
                    "skipped": [],
                    "skipped_count": 0,
                    "skipped_truncated": false
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/upload_sessions/{session_id}/uploads": {
      "post": {
        "operationId": "addUploadSessionFiles",
        "tags": [
          "Files"
        ],
        "summary": "Get storage targets for a batch",
        "description": "Returns upload.url and upload.headers for each file that needs bytes. Repeating a path returns a fresh target, for example after a failed PUT. Files with identical content are skipped.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^bus_"
            },
            "description": "bucket_upload_session.id from the create response."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "files"
                ],
                "properties": {
                  "files": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "$ref": "#/components/schemas/UploadSessionFile"
                    }
                  },
                  "account_id": {
                    "type": "string",
                    "description": "Select another granted account for this request."
                  },
                  "reason": {
                    "$ref": "#/components/schemas/ActionReason"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/UploadSessionResult"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/upload_sessions/{session_id}/finalize_batch": {
      "post": {
        "operationId": "saveUploadSessionBatch",
        "tags": [
          "Files"
        ],
        "summary": "Save uploaded files",
        "description": "Saves up to limit files whose bytes were uploaded. Call it after each batch to keep each request short. DIRECT_UPLOAD_NOT_FOUND names a file whose bytes are missing in error.details.path; upload it again and retry.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^bus_"
            },
            "description": "bucket_upload_session.id from the create response."
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 40,
                    "default": 40,
                    "description": "Files to save in this request."
                  },
                  "account_id": {
                    "type": "string",
                    "description": "Select another granted account for this request."
                  },
                  "reason": {
                    "$ref": "#/components/schemas/ActionReason"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/UploadSessionResult"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/upload_sessions/{session_id}/finalize": {
      "post": {
        "operationId": "finalizeUploadSession",
        "tags": [
          "Files"
        ],
        "summary": "Finish or cancel a batch upload",
        "description": "complete=true saves the remaining uploaded files, creates one bucket version and releases the lock. A 202 response with finalize_pending=true means more files remain: call finalize again after Retry-After. complete=false cancels the session and discards its unsaved files. Finalizing a finished session returns it unchanged.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^bus_"
            },
            "description": "bucket_upload_session.id from the create response."
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "complete": {
                    "type": "boolean",
                    "default": true,
                    "description": "false cancels the session."
                  },
                  "account_id": {
                    "type": "string",
                    "description": "Select another granted account for this request."
                  },
                  "reason": {
                    "$ref": "#/components/schemas/ActionReason"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/UploadSessionResult"
                    }
                  }
                }
              }
            }
          },
          "202": {
            "description": "More files remain; call finalize again",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/UploadSessionResult"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/publication": {
      "get": {
        "operationId": "getPublication",
        "tags": [
          "Publications"
        ],
        "summary": "Get the site",
        "description": "Returns the bucket's site and its build state.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          }
        ],
        "responses": {
          "200": {
            "description": "The site",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "publication"
                      ],
                      "properties": {
                        "publication": {
                          "$ref": "#/components/schemas/Publication"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "operationId": "publishBucket",
        "tags": [
          "Publications"
        ],
        "summary": "Publish the site",
        "description": "Publishes the bucket's files as its site, or republishes them. The build runs in the background: get the site until publish_state is ready or failed. Uses credits; see https://app.revdoku.com/pricing.json.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublishRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Publishing started",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "publication"
                      ],
                      "properties": {
                        "publication": {
                          "$ref": "#/components/schemas/Publication"
                        },
                        "plan_notice": {
                          "type": "object",
                          "description": "Present when site settings of the bucket stay preview-only on the current plan.",
                          "properties": {
                            "message": {
                              "type": "string",
                              "description": "What stays preview-only and how to apply it."
                            },
                            "required_plan": {
                              "type": "string",
                              "description": "The plan that applies the settings to the live site."
                            },
                            "upgrade_plan_name": {
                              "type": "string",
                              "description": "The same plan name, for upgrade buttons."
                            },
                            "upgrade_url": {
                              "type": "string",
                              "format": "uri",
                              "description": "The pricing page."
                            },
                            "preview_available": {
                              "type": "boolean",
                              "description": "True: a preview shows the settings."
                            },
                            "requirements": {
                              "type": "array",
                              "description": "The settings that stay preview-only.",
                              "items": {
                                "type": "object",
                                "additionalProperties": true
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "Not enough credits. Nothing was built. Do not retry automatically.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "INSUFFICIENT_CREDITS",
                    "message": "Not enough credits to publish: it needs 10 and the account has 4.",
                    "details": {
                      "credits_required": 10,
                      "credits_available": 4,
                      "upgrade_url": "https://app.revdoku.com/pricing?utm_source=limit_error&utm_content=credits"
                    },
                    "request_id": "req_example",
                    "next_action": "upgrade_plan"
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "operationId": "unpublishBucket",
        "tags": [
          "Publications"
        ],
        "summary": "Unpublish the site",
        "description": "Takes the site down. The bucket's files stay.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          }
        ],
        "responses": {
          "202": {
            "description": "Unpublishing started",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "publication"
                      ],
                      "properties": {
                        "publication": {
                          "$ref": "#/components/schemas/Publication"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/publication/preview": {
      "get": {
        "operationId": "getPublicationPreview",
        "tags": [
          "Publications"
        ],
        "summary": "Get the preview",
        "description": "Returns the bucket's latest preview and its build state.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          }
        ],
        "responses": {
          "200": {
            "description": "The preview",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "publication"
                      ],
                      "properties": {
                        "publication": {
                          "$ref": "#/components/schemas/Publication"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "operationId": "previewBucket",
        "tags": [
          "Publications"
        ],
        "summary": "Preview the site",
        "description": "Publishes the bucket's current files at a separate preview address for 24 hours. With branch, the preview shows that branch of the connected GitHub repository at preview-<branch>-<site>. The site does not change. Uses credits; see https://app.revdoku.com/pricing.json.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PreviewRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Preview build started",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "publication"
                      ],
                      "properties": {
                        "publication": {
                          "$ref": "#/components/schemas/Publication"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "Not enough credits. Nothing was built. Do not retry automatically.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                },
                "example": {
                  "success": false,
                  "error": {
                    "code": "INSUFFICIENT_CREDITS",
                    "message": "Not enough credits to publish: it needs 10 and the account has 4.",
                    "details": {
                      "credits_required": 10,
                      "credits_available": 4,
                      "upgrade_url": "https://app.revdoku.com/pricing?utm_source=limit_error&utm_content=credits"
                    },
                    "request_id": "req_example",
                    "next_action": "upgrade_plan"
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/account/github/installations": {
      "get": {
        "operationId": "listGithubInstallations",
        "tags": [
          "GitHub"
        ],
        "summary": "List connected GitHub accounts",
        "description": "Returns the GitHub accounts and organizations where a person installed the Revdoku GitHub App for this account. Each one reads the repositories that its owner chose on GitHub. Needs an account owner or administrator key with admin access to all buckets. To add a GitHub account, get the links with getGithubSetupLink.",
        "parameters": [
          {
            "$ref": "#/components/parameters/AccountId"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "Connected GitHub accounts",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "installations",
                        "pagination"
                      ],
                      "properties": {
                        "installations": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/GithubInstallation"
                          }
                        },
                        "pagination": {
                          "$ref": "#/components/schemas/Pagination"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "installations": [
                      {
                        "installation_id": 51234567,
                        "github_account_login": "acme",
                        "github_account_type": "Organization",
                        "settings_url": "https://github.com/organizations/acme/settings/installations/51234567",
                        "repository_selection": "selected"
                      }
                    ],
                    "pagination": {
                      "limit": 50,
                      "has_more": false,
                      "next_cursor": null
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/account/github/installations/{installation_id}/repositories": {
      "get": {
        "operationId": "listGithubRepositories",
        "tags": [
          "GitHub"
        ],
        "summary": "List the repositories of a GitHub account",
        "description": "Returns the repositories that one connected GitHub account lets Revdoku read, A-Z by full name. A repository that is not listed needs access on GitHub: give the account's settings_url to its owner. Needs an account owner or administrator key with admin access to all buckets.",
        "parameters": [
          {
            "$ref": "#/components/parameters/InstallationId"
          },
          {
            "$ref": "#/components/parameters/AccountId"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "Repositories",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "repositories",
                        "pagination"
                      ],
                      "properties": {
                        "repositories": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/GithubRepository"
                          }
                        },
                        "pagination": {
                          "$ref": "#/components/schemas/Pagination"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/github": {
      "get": {
        "operationId": "getGithubSync",
        "tags": [
          "GitHub"
        ],
        "summary": "Read the GitHub repository of a bucket",
        "description": "Returns the bucket's GitHub repository and its sync state. github is null when the bucket never had one. After connectGithubRepository, read it until last_synced_at is set (the first copy is done) or sync_state is error.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/AccountId"
          }
        ],
        "responses": {
          "200": {
            "description": "The GitHub repository of the bucket",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "github"
                      ],
                      "properties": {
                        "github": {
                          "anyOf": [
                            {
                              "$ref": "#/components/schemas/GithubSync"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "github": {
                      "id": "bgh_8xQ2kL4mN7pR",
                      "bucket_id": "bkt_5Gh3Lm9Qx2Tz",
                      "installation_id": 51234567,
                      "repo_owner": "acme",
                      "repo_name": "docs",
                      "repo_full_name": "acme/docs",
                      "repository_url": "https://github.com/acme/docs",
                      "branch": "main",
                      "repo_path": null,
                      "sync_state": "idle",
                      "last_error": null,
                      "next_retry_at": null,
                      "last_synced_at": "2026-11-09T10:15:00Z",
                      "last_synced_commit_sha": "4f1c2e9a7b3d5f6081a2c3d4e5f60718293a4b5c",
                      "last_synced_commit_message": "Add the quickstart page",
                      "auto_publish": true,
                      "push_revdoku_edits": false,
                      "auto_commit": false,
                      "pending_count": 0,
                      "pending_changes": [],
                      "pull_request": null,
                      "skipped_files": [],
                      "auto_publish_error": null,
                      "dashboard_url": "https://app.revdoku.com/buckets/view?account_id=acct_3Fh8Qm2Lx9Tw&id=bkt_5Gh3Lm9Qx2Tz&site=github&view=site",
                      "created_at": "2026-11-09T10:14:20Z",
                      "updated_at": "2026-11-09T10:15:00Z"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "operationId": "connectGithubRepository",
        "tags": [
          "GitHub"
        ],
        "summary": "Connect a GitHub repository",
        "description": "Makes the bucket's files a copy of one branch of a repository, or of one folder of it. The first sync copies the files, and each later push to the branch updates them. The bucket must have no files of its own; its email and agent folders may stay. GitHub stays the source: Revdoku never copies a bucket into a repository. Needs an account owner or administrator key with admin access to all buckets. A connected GitHub account must read the repository: 403 GITHUB_APP_NOT_INSTALLED gives the links for the person in error.details.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "github": {
                    "$ref": "#/components/schemas/GithubConnect"
                  },
                  "account_id": {
                    "type": "string",
                    "description": "Select another granted account for this request."
                  },
                  "reason": {
                    "$ref": "#/components/schemas/ActionReason"
                  }
                },
                "required": [
                  "github"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Connected. The first sync is queued",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "github"
                      ],
                      "properties": {
                        "github": {
                          "$ref": "#/components/schemas/GithubSync"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "patch": {
        "operationId": "updateGithubSync",
        "tags": [
          "GitHub"
        ],
        "summary": "Change GitHub sync settings",
        "description": "Sets auto_publish and the mode of edits made in Revdoku: push_revdoku_edits false makes the files a read-only copy, auto_commit true commits edits to the branch at each sync, and auto_commit false keeps them in pending_changes until a person publishes them in the dashboard. Needs an account owner or administrator key with admin access to all buckets.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "github": {
                    "$ref": "#/components/schemas/GithubSyncSettings"
                  },
                  "account_id": {
                    "type": "string",
                    "description": "Select another granted account for this request."
                  },
                  "reason": {
                    "$ref": "#/components/schemas/ActionReason"
                  }
                },
                "required": [
                  "github"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The changed settings",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "github"
                      ],
                      "properties": {
                        "github": {
                          "$ref": "#/components/schemas/GithubSync"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "operationId": "disconnectGithubRepository",
        "tags": [
          "GitHub"
        ],
        "summary": "Disconnect the GitHub repository",
        "description": "Stops the sync. The bucket keeps its files and its site. A later read shows the link with sync_state disconnected; connect the same repository again to continue its copy. Needs an account owner or administrator key with admin access to all buckets.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/AccountId"
          },
          {
            "$ref": "#/components/parameters/Reason"
          }
        ],
        "responses": {
          "200": {
            "description": "Disconnected",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/DeleteResult"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/github/sync": {
      "post": {
        "operationId": "syncGithubRepository",
        "tags": [
          "GitHub"
        ],
        "summary": "Sync the GitHub repository now",
        "description": "Copies new commits of the branch now and tries a failed sync again. Pushes sync without this call; use it after an error, or after a person changed access on GitHub. enqueued is false when a sync already runs. Needs an account owner or administrator key with admin access to all buckets.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ActionRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Sync queued",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "github",
                        "enqueued"
                      ],
                      "properties": {
                        "github": {
                          "$ref": "#/components/schemas/GithubSync"
                        },
                        "enqueued": {
                          "type": "boolean",
                          "description": "False when a sync already runs."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/github/branches": {
      "get": {
        "operationId": "listGithubBranches",
        "tags": [
          "GitHub"
        ],
        "summary": "List the branches that can get a preview",
        "description": "Returns the branches of the bucket's GitHub repository, without the linked branch (the site shows it), A-Z. Pass one as branch to previewBucket. Requires bucket publish permission. 404 GITHUB_SYNC_NOT_CONNECTED without a repository.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/AccountId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "branches"
                      ],
                      "properties": {
                        "branches": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "branches": [
                      "next",
                      "pricing-page"
                    ]
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/buckets/{bucket_id}/github/setup_link": {
      "get": {
        "operationId": "getGithubSetupLink",
        "tags": [
          "GitHub"
        ],
        "summary": "Get the links to add a GitHub account",
        "description": "Returns the links that a person opens to add a GitHub account or organization to this Revdoku account. Only the person who owns this key or AI connection can finish the step, signed in to Revdoku, within 30 minutes. Give install_url to install the Revdoku GitHub App; on GitHub the person chooses the account and the repositories. Give authorization_url when the App is already installed on that GitHub account; the person then selects Connect on the bucket's GitHub page. Then list the connected GitHub accounts until the new one shows. Needs an account owner or administrator key with admin access to all buckets.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BucketId"
          },
          {
            "$ref": "#/components/parameters/AccountId"
          }
        ],
        "responses": {
          "200": {
            "description": "Links for the person",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "setup_link"
                      ],
                      "properties": {
                        "setup_link": {
                          "$ref": "#/components/schemas/GithubSetupLink"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Authorization: Bearer YOUR_API_KEY. Create a key in the dashboard under Account → Access."
      }
    },
    "schemas": {
      "ActionReason": {
        "type": [
          "string",
          "null"
        ],
        "maxLength": 2000,
        "description": "Optional purpose for this action. AI agents should explain intentional reads and changes when known; omit when unknown. Do not include secrets, file contents, or transcripts."
      },
      "Pagination": {
        "type": "object",
        "description": "One page of a list. Request the next page with cursor=next_cursor and the same filters. Cursors are opaque strings: do not build or decode them.",
        "required": [
          "limit",
          "has_more",
          "next_cursor"
        ],
        "properties": {
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 200
          },
          "has_more": {
            "type": "boolean",
            "description": "True when another page exists."
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Cursor for the next page; null on the last page. Email lists always return a cursor so that you can poll for new mail."
          }
        }
      },
      "DeleteResult": {
        "type": "object",
        "required": [
          "deleted",
          "id"
        ],
        "properties": {
          "deleted": {
            "type": "boolean",
            "const": true
          },
          "id": {
            "type": "string",
            "description": "ID of the deleted resource. A webhook delete returns the bucket ID."
          }
        }
      },
      "Download": {
        "type": "object",
        "description": "Temporary download link. Fetch url without an API key. Request a new link after it expires.",
        "required": [
          "url",
          "filename",
          "content_type",
          "expires_in",
          "size_bytes"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          },
          "filename": {
            "type": "string"
          },
          "content_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "expires_in": {
            "type": "integer",
            "const": 900,
            "description": "Seconds until the link expires."
          },
          "size_bytes": {
            "type": "integer",
            "minimum": 0,
            "format": "int64"
          }
        }
      },
      "ErrorCode": {
        "type": "string",
        "description": "Documented values of error.code. Treat an unknown code as a generic failure for its HTTP status.",
        "enum": [
          "ACCOUNT_ACCESS_UNAVAILABLE",
          "ACCOUNT_ADMIN_REQUIRED",
          "ACCOUNT_CONNECTION_LIMIT_REACHED",
          "ACCOUNT_FILE_LIMIT_EXCEEDED",
          "ACCOUNT_READ_ONLY",
          "ACCOUNT_SELECTOR_CONFLICT",
          "ACCOUNT_SUSPENDED",
          "AGENCY_ACCOUNT_REQUIRED",
          "AGENT_CONNECTION_LIMIT_REACHED",
          "BUCKETS_NOT_FOUND",
          "BUCKET_ACCESS_DENIED",
          "BUCKET_ACCOUNT_CHANGED",
          "BUCKET_ALREADY_ARCHIVED",
          "BUCKET_ARCHIVED",
          "BUCKET_CREATION_LIMIT_REACHED",
          "BUCKET_DELETE_ADMIN_REQUIRED",
          "BUCKET_DELETE_BUSY",
          "BUCKET_DELETE_CONFIRMATION_REQUIRED",
          "BUCKET_DELETE_ENQUEUE_FAILED",
          "BUCKET_DELETE_IN_PROGRESS",
          "BUCKET_FILE_DELETE_ENQUEUE_FAILED",
          "BUCKET_FILE_LIMIT_EXCEEDED",
          "BUCKET_FILE_NOT_FOUND",
          "BUCKET_FILE_PATH_EXISTS",
          "BUCKET_FILE_VERSION_NOT_FOUND",
          "BUCKET_LIMIT_REACHED",
          "BUCKET_LOCKED",
          "BUCKET_METADATA_CONFLICT",
          "BUCKET_MOVING",
          "BUCKET_NOT_ARCHIVED",
          "BUCKET_NOT_FOUND",
          "BUCKET_PERMISSION_DENIED",
          "BUCKET_PUBLICATION_ACTIVE",
          "BUCKET_PUBLICATION_SUSPENDED",
          "BUCKET_TITLE_TAKEN",
          "BUCKET_TOO_LARGE",
          "BUCKET_UNAVAILABLE",
          "BUCKET_UPLOAD_EXISTING_FILE_SKIPPED",
          "BUCKET_UPLOAD_FILE_ALREADY_FINALIZED",
          "BUCKET_UPLOAD_FILE_FAILED",
          "BUCKET_UPLOAD_FILE_SKIPPED",
          "BUCKET_UPLOAD_SESSION_CANCELED",
          "BUCKET_UPLOAD_SESSION_EXPIRED",
          "BUCKET_UPLOAD_SESSION_INCOMPLETE",
          "BUCKET_UPLOAD_SESSION_LOCK_LOST",
          "BUCKET_UPLOAD_SESSION_NOT_PENDING",
          "BUCKET_UPLOAD_SHA256_MISMATCH",
          "BUCKET_UPLOAD_SIZE_MISMATCH",
          "BUCKET_VERSION_CONFLICT",
          "BUCKET_VISIBILITY_CHANGE_LOCKED",
          "CLIENT_ACCOUNT_LIMIT_REACHED",
          "CONFLICT",
          "CONTENT_SEARCH_DISABLED",
          "DATABASE_BUSY_RETRY",
          "DIRECT_UPLOAD_ACCOUNT_MISMATCH",
          "DIRECT_UPLOAD_ALREADY_ATTACHED",
          "DIRECT_UPLOAD_ENCRYPTED",
          "DIRECT_UPLOAD_NOT_FOUND",
          "DIRECT_UPLOAD_PURPOSE_MISMATCH",
          "DIRECT_UPLOAD_REQUIRED",
          "DUPLICATE_FILE_VERSION",
          "EMAIL_ACCOUNT_DISABLED",
          "EMAIL_ADDRESS_CHANGED",
          "EMAIL_ALIAS_BASE",
          "EMAIL_ALIAS_LIMIT",
          "EMAIL_ALLOWLIST_CHANGED",
          "EMAIL_ALLOWLIST_INVALID",
          "EMAIL_ALLOWLIST_UNAVAILABLE",
          "EMAIL_ALREADY_EXISTS",
          "EMAIL_ASSIGNMENT_EXPIRED",
          "EMAIL_ASSIGNMENT_FORBIDDEN",
          "EMAIL_ASSIGNMENT_PENDING",
          "EMAIL_ASSIGNMENT_UNAVAILABLE",
          "EMAIL_ATTACHMENT_NOT_FOUND",
          "EMAIL_BUCKET_UNAVAILABLE",
          "EMAIL_CHANGED",
          "EMAIL_DNS_CONFLICT",
          "EMAIL_DNS_TEMPORARY",
          "EMAIL_DOMAINS_UNAVAILABLE",
          "EMAIL_DOMAINS_UNCONFIGURED",
          "EMAIL_DOMAINS_UPGRADE_REQUIRED",
          "EMAIL_DOMAIN_CONFIRMATION_REQUIRED",
          "EMAIL_DOMAIN_INVALID",
          "EMAIL_DOMAIN_IN_USE",
          "EMAIL_DOMAIN_NOT_READY",
          "EMAIL_DOMAIN_NOT_REGISTERED",
          "EMAIL_DOMAIN_RATE_LIMIT",
          "EMAIL_DOMAIN_SETUP_UNAVAILABLE",
          "EMAIL_DOMAIN_SETUP_UNSUPPORTED",
          "EMAIL_DOMAIN_UNAVAILABLE",
          "EMAIL_INDEX_BUILDING",
          "EMAIL_LABELING_PENDING",
          "EMAIL_LOOP_DETECTED",
          "EMAIL_NAMES_UNAVAILABLE",
          "EMAIL_NAMES_UPGRADE_REQUIRED",
          "EMAIL_NAME_FORBIDDEN",
          "EMAIL_NAME_INVALID",
          "EMAIL_NOT_READY",
          "EMAIL_OWNERSHIP_PENDING",
          "MAILBOX_PATH_READ_ONLY",
          "EMAIL_PROVIDER_DNS_PENDING",
          "EMAIL_PROVIDER_PENDING",
          "EMAIL_PROVIDER_TEMPORARY",
          "EMAIL_READ_STATUS_UNAVAILABLE",
          "EMAIL_RECEIVING_PAUSED",
          "EMAIL_RECIPIENT_CAPACITY",
          "EMAIL_RECIPIENT_NOT_ALLOWED",
          "EMAIL_RECIPIENT_UNAVAILABLE",
          "EMAIL_REPLY_UPGRADE_REQUIRED",
          "EMAIL_ROTATION_LIMIT",
          "EMAIL_ROTATION_UNAVAILABLE",
          "EMAIL_SENDING_RULES_CHANGED",
          "EMAIL_SENDING_UNAVAILABLE",
          "EMAIL_SEND_LIMIT_REACHED",
          "EMAIL_SEND_RATE_LIMITED",
          "EMAIL_TOO_LARGE",
          "EMAIL_UNAVAILABLE",
          "EMAIL_WITHHELD",
          "EMPTY_FILE",
          "FILE_LOCKED",
          "FILE_TOO_LARGE",
          "FILE_VERSION_ALREADY_CURRENT",
          "FILE_VERSION_ENCRYPTION_MISMATCH",
          "FILE_VERSION_NOT_RESTORABLE",
          "FORBIDDEN",
          "GITHUB_APP_NOT_INSTALLED",
          "GITHUB_INSTALLATION_NOT_FOUND",
          "GITHUB_SYNC_BRANCH_UNAVAILABLE",
          "GITHUB_SYNC_BUCKET_NOT_EMPTY",
          "GITHUB_SYNC_DISABLED",
          "GITHUB_SYNC_ENCRYPTED_ACCOUNT",
          "GITHUB_SYNC_NOT_CONNECTED",
          "GITHUB_SYNC_REPO_TAKEN",
          "GITHUB_SYNC_REPO_UNAVAILABLE",
          "GITHUB_SYNC_UNAVAILABLE",
          "GITHUB_UNAVAILABLE",
          "INSUFFICIENT_CREDITS",
          "INTERNAL_ERROR",
          "INVALID_ARGUMENT",
          "INVALID_CHECKSUM",
          "INVALID_CODE",
          "INVALID_DIRECT_UPLOAD",
          "INVALID_GRANT",
          "INVALID_SHA256",
          "INVALID_TEXT_ENCODING",
          "LOCKED",
          "MIME_TYPE_MISMATCH",
          "NOT_FOUND",
          "OTP_RATE_LIMITED",
          "PAYLOAD_TOO_LARGE",
          "PRIVATE_PUBLICATION_LIMIT_REACHED",
          "PRIVATE_PUBLICATION_STORAGE_NOT_CONFIGURED",
          "PROHIBITED_FILE_EXTENSION",
          "PROJECT_STORAGE_QUOTA_EXCEEDED",
          "PUBLICATION_ACCESS_MODE_INVALID",
          "PUBLICATION_ACCESS_MODE_NOT_SUPPORTED",
          "PUBLICATION_FAILED",
          "PUBLICATION_LIMIT_REACHED",
          "PUBLICATION_LIVE",
          "PUBLICATION_NOT_FOUND",
          "PUBLICATION_PASSWORD_INVALID",
          "PUBLICATION_POLICY_REVIEW",
          "PUBLICATION_PUBLISH_IN_PROGRESS",
          "PUBLICATION_SOURCE_CHANGED",
          "PUBLICATION_SUSPENDED",
          "PUBLICATION_UPGRADE_REQUIRED",
          "PUBLIC_STORAGE_NOT_CONFIGURED",
          "PUBLISH_COOLDOWN",
          "PUBLISH_RATE_LIMIT_EXCEEDED",
          "RATE_LIMIT_EXCEEDED",
          "REPUBLISH_LIMIT_REACHED",
          "RESERVED_PATH",
          "SERVICE_UNAVAILABLE",
          "STORAGE_QUOTA_EXCEEDED",
          "UNAUTHORIZED",
          "UNSUPPORTED_MIME",
          "UNSUPPORTED_TEXT_APPEND_TYPE",
          "UPLOAD_RATE_LIMIT_EXCEEDED",
          "VERSION_ROLLBACK_UNAVAILABLE",
          "WEBSITE_PREVIEW_UNAVAILABLE",
          "WEBSITE_PUBLISHING_DISABLED",
          "EMAIL_LOCKED",
          "PUBLIC_SLUG_REQUIRES_CHANGE",
          "SYNCED_COPY_READ_ONLY"
        ]
      },
      "ApiError": {
        "type": "object",
        "properties": {
          "success": {
            "const": false
          },
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "minLength": 1,
                "description": "Stable error identifier. See ErrorCode for the documented values. Invalid input always returns INVALID_ARGUMENT with HTTP 422."
              },
              "message": {
                "type": "string",
                "minLength": 1
              },
              "details": {
                "oneOf": [
                  {
                    "type": "object",
                    "additionalProperties": true
                  },
                  {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "field": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "field",
                        "message"
                      ]
                    }
                  }
                ]
              },
              "request_id": {
                "type": "string"
              },
              "docs_url": {
                "type": "string",
                "format": "uri"
              },
              "timestamp": {
                "type": "string",
                "format": "date-time"
              },
              "recoverable": {
                "type": "boolean"
              },
              "next_action": {
                "type": "string"
              },
              "browser_url": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ]
          }
        },
        "required": [
          "success",
          "error"
        ],
        "not": {
          "anyOf": [
            {
              "required": [
                "data"
              ]
            },
            {
              "required": [
                "error_message"
              ]
            }
          ]
        }
      },
      "AccountIdentity": {
        "type": "object",
        "required": [
          "id",
          "name",
          "account_kind",
          "client_name",
          "agency_account"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "description": "Account name, separate from the client person or business."
          },
          "account_kind": {
            "type": "string",
            "enum": [
              "standard",
              "agency",
              "client"
            ]
          },
          "client_name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 100,
            "description": "Client person or business name, or null when unset."
          },
          "agency_account": {
            "type": [
              "object",
              "null"
            ],
            "description": "Parent agency only when granted to this credential. Null does not make a client independent.",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            }
          },
          "region": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "read_only"
            ]
          },
          "permissions": {
            "type": "object",
            "properties": {
              "scope": {
                "type": "string",
                "enum": [
                  "bucket_read",
                  "bucket_write",
                  "bucket_admin"
                ]
              },
              "bucket_access": {
                "type": "string",
                "enum": [
                  "all",
                  "selected"
                ]
              },
              "can_create_buckets": {
                "type": "boolean"
              }
            }
          }
        }
      },
      "AccountList": {
        "type": "object",
        "required": [
          "accounts",
          "default_account_id",
          "pagination"
        ],
        "properties": {
          "accounts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AccountIdentity"
            }
          },
          "default_account_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Account used when a request does not send account_id."
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "AccountLimits": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "max_buckets",
          "max_bucket_creations_per_month",
          "max_files_per_bucket",
          "max_current_files",
          "max_storage_bytes",
          "max_file_size_bytes",
          "max_pdf_size_bytes",
          "max_file_versions_per_file",
          "max_email_domains",
          "max_received_emails_per_month",
          "max_received_email_bytes_per_month",
          "max_received_email_message_bytes",
          "max_sent_emails_per_month",
          "max_email_address_rotations_per_month",
          "max_account_members",
          "max_api_keys",
          "max_agent_connections",
          "api_rate_limit_requests_per_minute",
          "audit_retention_days",
          "max_email_aliases_per_bucket"
        ],
        "properties": {
          "max_buckets": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "max_bucket_creations_per_month": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "max_files_per_bucket": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "max_current_files": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "max_storage_bytes": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "format": "int64"
          },
          "max_file_size_bytes": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "format": "int64"
          },
          "max_pdf_size_bytes": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "format": "int64"
          },
          "max_file_versions_per_file": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "max_email_domains": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "max_received_emails_per_month": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "max_received_email_bytes_per_month": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "format": "int64"
          },
          "max_received_email_message_bytes": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "format": "int64"
          },
          "max_sent_emails_per_month": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Sent-email recipients per billing period, shared by the billing group. Each recipient counts once."
          },
          "max_email_address_rotations_per_month": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "max_account_members": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "max_api_keys": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "max_agent_connections": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "api_rate_limit_requests_per_minute": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "audit_retention_days": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "max_email_aliases_per_bucket": {
            "type": "integer",
            "minimum": 0,
            "description": "Active retained email addresses (aliases) per bucket. Zero means that the plan has no aliases."
          }
        }
      },
      "Connection": {
        "type": "object",
        "properties": {
          "api_key_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "label": {
            "type": [
              "string",
              "null"
            ]
          },
          "token_type": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "api",
              null
            ]
          },
          "scope": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "bucket_read",
              "bucket_write",
              "bucket_admin",
              null
            ]
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "last_used_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "bucket_access": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "all",
              "selected",
              null
            ]
          },
          "bucket_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "denied_bucket_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "bucket_permissions": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "permissions": {
            "type": "object",
            "properties": {
              "read": {
                "type": "boolean"
              },
              "write": {
                "type": "boolean"
              },
              "admin": {
                "type": "boolean"
              }
            }
          },
          "agent": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true
          },
          "transport": {
            "type": [
              "string",
              "null"
            ]
          },
          "renewal": {
            "type": "object",
            "properties": {
              "recommended": {
                "type": "boolean"
              },
              "next_action": {
                "type": "string"
              },
              "browser_url": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "Status": {
        "type": "object",
        "properties": {
          "connected": {
            "type": "boolean"
          },
          "account": {
            "type": "object",
            "additionalProperties": true,
            "description": "Selected account identity and state."
          },
          "default_account_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "accounts": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "server_version": {
            "type": "string"
          },
          "client_version": {
            "type": "string",
            "description": "Current CLI and skill release."
          },
          "features": {
            "type": "object",
            "properties": {
              "email_domains": {
                "type": "boolean"
              }
            }
          },
          "connection": {
            "$ref": "#/components/schemas/Connection"
          },
          "user": {
            "type": "object",
            "description": "The signed-in person behind this credential.",
            "properties": {
              "id": {
                "type": "string"
              },
              "email": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            }
          },
          "dashboard_url": {
            "type": "string",
            "format": "uri",
            "description": "Dashboard link for the selected account. It grants no access."
          }
        },
        "required": [
          "connected",
          "account",
          "connection"
        ]
      },
      "BucketAction": {
        "type": "object",
        "properties": {
          "allowed": {
            "type": "boolean"
          },
          "blocked_reason": {
            "type": "string"
          },
          "required_action": {
            "type": "string"
          },
          "confirmation": {
            "type": "string",
            "description": "Delete only: send this value as confirmation in DELETE /v1/buckets/{bucket_id} after the user confirms."
          }
        },
        "required": [
          "allowed"
        ]
      },
      "BucketEmail": {
        "type": "object",
        "description": "The bucket's email address and whether it can receive and send now. Counts read the email index without reading content.",
        "required": [
          "message_count",
          "unread_count",
          "last_received_at",
          "receiving_enabled",
          "sending_enabled"
        ],
        "properties": {
          "address": {
            "type": "string",
            "description": "Primary address. Present when the credential has write access to the bucket. Show it after the title."
          },
          "message_count": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "minimum": 0,
            "description": "Emails currently stored. Null while the email index is being prepared."
          },
          "unread_count": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "minimum": 0,
            "description": "Stored emails with shared unread status. Null while the email index is being prepared."
          },
          "last_received_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Receipt time of the latest saved email; null before the first email."
          },
          "receiving_enabled": {
            "type": "boolean",
            "description": "Whether the address can receive email now."
          },
          "receiving_blocked_reason": {
            "type": "string",
            "description": "Why receiving is unavailable. Omitted when receiving_enabled is true."
          },
          "sending_enabled": {
            "type": "boolean",
            "description": "Whether the bucket can send replies now."
          },
          "sending_blocked_reason": {
            "type": "string",
            "description": "Why sending is unavailable. Omitted when sending_enabled is true."
          }
        }
      },
      "BucketLock": {
        "type": "object",
        "required": [
          "locked"
        ],
        "properties": {
          "locked": {
            "type": "boolean"
          },
          "locked_until": {
            "type": "string",
            "format": "date-time"
          },
          "kind": {
            "type": "string",
            "description": "For example bucket_delete while a permanent delete runs."
          },
          "message": {
            "type": "string"
          },
          "progress": {
            "type": "object",
            "additionalProperties": true
          },
          "locked_by": {
            "$ref": "#/components/schemas/FileActor"
          },
          "locked_by_api_key": {
            "$ref": "#/components/schemas/FileKey"
          }
        }
      },
      "Bucket": {
        "type": "object",
        "description": "A bucket: private files, its own email address, and a site. Label it as title (email.address), or by email.address alone when title is null. Use id in API calls.",
        "required": [
          "id",
          "account_id",
          "email",
          "archived",
          "version_id",
          "version_number",
          "metadata_version",
          "archive",
          "unarchive",
          "delete"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^bkt_"
          },
          "account_id": {
            "type": "string"
          },
          "title": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 255,
            "description": "Bucket title chosen by people. Defaults to the email username given at creation. Null when unset or when the caller cannot see email.address."
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true,
            "description": "Your application data. PATCH replaces the whole object."
          },
          "metadata_version": {
            "type": "string",
            "description": "Send as expected_metadata_version on PATCH. Changes only when description or metadata changes."
          },
          "email": {
            "$ref": "#/components/schemas/BucketEmail"
          },
          "archived": {
            "type": "boolean"
          },
          "archived_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "lock": {
            "$ref": "#/components/schemas/BucketLock"
          },
          "storage_bytes": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "files_count": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Current files, including stored emails and attachments."
          },
          "version_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Current bucket file-tree version. Send as expected_bucket_version on file writes to detect concurrent changes."
          },
          "version_number": {
            "type": "integer",
            "minimum": 0
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "dashboard_url": {
            "type": "string",
            "format": "uri",
            "description": "Opens the bucket for signed-in members. It does not grant access."
          },
          "archive": {
            "$ref": "#/components/schemas/BucketAction"
          },
          "unarchive": {
            "$ref": "#/components/schemas/BucketAction"
          },
          "delete": {
            "$ref": "#/components/schemas/BucketAction"
          }
        }
      },
      "BucketCounts": {
        "type": "object",
        "description": "Exact authorized bucket totals after query filtering, before status filtering and pagination.",
        "properties": {
          "active": {
            "type": "integer",
            "minimum": 0,
            "format": "int64"
          },
          "archived": {
            "type": "integer",
            "minimum": 0,
            "format": "int64"
          },
          "total": {
            "type": "integer",
            "minimum": 0,
            "format": "int64"
          }
        },
        "required": [
          "active",
          "archived",
          "total"
        ]
      },
      "BucketList": {
        "type": "object",
        "required": [
          "buckets",
          "counts",
          "pagination"
        ],
        "properties": {
          "buckets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Bucket"
            }
          },
          "counts": {
            "$ref": "#/components/schemas/BucketCounts"
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "BucketEmailOptions": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "username": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "description": "On revdokumail.com, every plan: the bucket's name, with no suffix and the same name as its site. Dots and underscores become hyphens; it needs 3 to 63 lowercase letters, digits and single hyphens (fewer than 3 returns EMAIL_NAME_INVALID). On a custom domain: the exact name before @, normalized to lowercase. Omit to use the title's name or two readable words; blank/null is invalid. Unavailable names return EMAIL_ALREADY_EXISTS."
          },
          "domain": {
            "type": "string",
            "description": "Built-in domain such as revdokumail.com on any plan, or a ready custom email domain owned by the selected account on an eligible plan. Omit for the default platform domain."
          }
        }
      },
      "BucketCreate": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 255,
            "description": "Optional title. Defaults to email.username as given, or to the generated name. A title that another active bucket uses returns 409 BUCKET_TITLE_TAKEN."
          },
          "description": {
            "type": "string",
            "maxLength": 2000
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true
          },
          "email": {
            "$ref": "#/components/schemas/BucketEmailOptions"
          }
        }
      },
      "BucketUpdate": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "title": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 255,
            "description": "New title. An empty string or null clears it. A title that another active bucket uses returns 409 BUCKET_TITLE_TAKEN."
          },
          "description": {
            "type": "string",
            "maxLength": 2000
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "Webhook": {
        "type": "object",
        "required": [
          "url",
          "events"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "ticket.created",
                "ticket.message_received"
              ]
            },
            "description": "The event types that the webhook receives."
          }
        }
      },
      "WebhookWithSecret": {
        "type": "object",
        "required": [
          "url",
          "events"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "ticket.created",
                "ticket.message_received"
              ]
            },
            "description": "The event types that the webhook receives."
          },
          "signing_secret": {
            "type": "string",
            "description": "Returned once, when this request issues a secret: a new URL or rotate_secret=true. Store it to verify signatures."
          }
        }
      },
      "EventSubscription": {
        "type": "object",
        "required": [
          "token",
          "expires_in",
          "channel",
          "account_id",
          "bucket_id",
          "websocket_url"
        ],
        "properties": {
          "token": {
            "type": "string"
          },
          "expires_in": {
            "type": "integer",
            "const": 60
          },
          "channel": {
            "type": "string",
            "const": "BucketEventsChannel"
          },
          "account_id": {
            "type": "string"
          },
          "bucket_id": {
            "type": "string"
          },
          "websocket_url": {
            "type": "string",
            "format": "uri",
            "description": "Base WebSocket endpoint. Append subscription_token as a query parameter."
          }
        }
      },
      "TicketEvent": {
        "type": "object",
        "description": "A ticket event, sent to the webhook and to live subscribers. ticket.created is the first message of a new ticket; ticket.message_received is a later message of a ticket. While the AI filter is on for the account, an event waits until the filter has checked the message, at most one minute. A message that the filter labels Junk sends no event; if a person removes the Junk label, the event is sent then. Events carry only IDs: read the ticket with GET /v1/buckets/{bucket_id}/tickets/{ticket_id}.",
        "required": [
          "id",
          "type",
          "created_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable event ID; deduplicate across retries."
          },
          "type": {
            "type": "string",
            "enum": [
              "ticket.created",
              "ticket.message_received"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "type": "object",
            "required": [
              "account_id",
              "bucket_id",
              "ticket_id",
              "message_id",
              "channel",
              "received_at",
              "attachment_count"
            ],
            "properties": {
              "account_id": {
                "type": "string"
              },
              "bucket_id": {
                "type": "string"
              },
              "ticket_id": {
                "type": [
                  "string",
                  "null"
                ],
                "pattern": "^tkt_",
                "description": "The ticket of the message."
              },
              "message_id": {
                "type": "string",
                "pattern": "^eml_",
                "description": "The new message (GET /v1/buckets/{bucket_id}/tickets/{ticket_id}/messages/{message_id})."
              },
              "channel": {
                "type": "string",
                "enum": [
                  "email",
                  "chat",
                  "feedback"
                ],
                "description": "How the message arrived: an email, a message left on the docs site or page feedback."
              },
              "received_at": {
                "type": "string",
                "format": "date-time"
              },
              "attachment_count": {
                "type": "integer",
                "minimum": 0
              }
            }
          }
        }
      },
      "DecodedEmailAddress": {
        "type": "object",
        "required": [
          "address",
          "name"
        ],
        "properties": {
          "address": {
            "type": "string"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "EmailForwarding": {
        "type": "object",
        "description": "Server-recorded member forwarding provenance. The original author is reported by the member, not independently authenticated. Absent for ordinary or unrecognized mail.",
        "required": [
          "attribution",
          "method",
          "parser_version",
          "member_id",
          "member_email",
          "intake_account_id"
        ],
        "properties": {
          "method": {
            "type": "string"
          },
          "member_id": {
            "type": "string"
          },
          "member_email": {
            "type": "string"
          },
          "intake_account_id": {
            "type": "string"
          },
          "outer_from": {
            "type": "string"
          },
          "outer_subject": {
            "type": "string"
          },
          "outer_message_id": {
            "type": "string"
          },
          "original_date_raw": {
            "type": "string"
          },
          "original_sent_at": {
            "type": "string"
          },
          "attribution": {
            "type": "string",
            "const": "member_forwarded"
          },
          "parser_version": {
            "type": "integer",
            "minimum": 1,
            "description": "Parser implementation used at intake; does not change the forwarding response shape."
          }
        }
      },
      "EmailForwardingContent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EmailForwarding"
          },
          {
            "type": "object",
            "properties": {
              "note_text": {
                "type": "string",
                "description": "Separate member note, bounded to 64 KiB. Never part of the original body."
              },
              "note_status": {
                "type": "string",
                "enum": [
                  "complete",
                  "empty",
                  "truncated",
                  "unavailable"
                ]
              }
            }
          }
        ]
      },
      "EmailDelivery": {
        "type": "object",
        "description": "Present on sent emails only.",
        "required": [
          "status",
          "recipients"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "awaiting_approval",
              "queued",
              "sending",
              "sent",
              "failed",
              "uncertain",
              "declined"
            ],
            "description": "awaiting_approval: a person sends, edits or declines the email in the dashboard; do not send it again. declined: a person declined it and it was not sent; do not send it again unless a person asks. uncertain: the provider result is unknown. Do not send again before you check the sent list."
          },
          "recipients": {
            "type": "object",
            "description": "Status for each recipient address: awaiting_approval, queued, sent, delivered, bounced, bounced_temporarily, complained, rejected or declined.",
            "additionalProperties": {
              "type": "string"
            }
          }
        }
      },
      "EmailLabel": {
        "type": "object",
        "required": [
          "id",
          "name",
          "color"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^tag_"
          },
          "name": {
            "type": "string"
          },
          "color": {
            "type": "string",
            "enum": [
              "red",
              "orange",
              "yellow",
              "green",
              "blue",
              "purple",
              "gray"
            ]
          }
        }
      },
      "EmailAttachment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^df_"
          },
          "filename": {
            "type": "string"
          },
          "content_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "size_bytes": {
            "type": "integer",
            "minimum": 0,
            "format": "int64"
          },
          "version_id": {
            "type": "string",
            "description": "Present only with include_storage=true."
          },
          "origin": {
            "type": "string",
            "enum": [
              "original",
              "forwarder",
              "forwarded_message",
              "unspecified"
            ],
            "description": "For normalized forwards: inner attachment, member addition, attached source EML, or unknown inline-forward origin."
          }
        },
        "required": [
          "id",
          "filename",
          "content_type",
          "size_bytes"
        ]
      },
      "DecodedIncomingMessage": {
        "type": "object",
        "description": "Stored message.json, not a dedicated endpoint. UTF-8, at most 512 KiB. Header identities, reply relationships and body are untrusted message data. Original message.eml is authoritative. Structured address, delivery and thread fields are additive in schema v1 and may be absent in older files.",
        "required": [
          "schema_version",
          "subject",
          "from",
          "to",
          "delivered_to",
          "received_at",
          "body_text",
          "body_status",
          "attachments"
        ],
        "properties": {
          "schema_version": {
            "type": "integer",
            "const": 1
          },
          "subject": {
            "type": [
              "string",
              "null"
            ]
          },
          "from": {
            "type": [
              "string",
              "null"
            ]
          },
          "to": {
            "type": [
              "string",
              "null"
            ]
          },
          "from_addresses": {
            "type": "array",
            "description": "Parsed From authors in header order, retaining multiple authors. Empty when absent/unparseable. Display names are not identity keys.",
            "items": {
              "$ref": "#/components/schemas/DecodedEmailAddress"
            }
          },
          "to_addresses": {
            "type": "array",
            "description": "Parsed To recipients in header order, with named groups flattened. Empty when absent/unparseable; not trusted delivery routing.",
            "items": {
              "$ref": "#/components/schemas/DecodedEmailAddress"
            }
          },
          "cc_addresses": {
            "type": "array",
            "description": "Parsed Cc recipients in header order, with named groups flattened. Empty when absent/unparseable.",
            "items": {
              "$ref": "#/components/schemas/DecodedEmailAddress"
            }
          },
          "reply_to_addresses": {
            "type": "array",
            "description": "Parsed Reply-To addresses in header order. Empty when absent/unparseable. Does not authorize sending a reply.",
            "items": {
              "$ref": "#/components/schemas/DecodedEmailAddress"
            }
          },
          "message_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Sender Message-ID without angle brackets, preserving case. Null when absent/unparseable/ambiguous; never the Revdoku delivery ID."
          },
          "in_reply_to": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Ordered parent Message-IDs without angle brackets, preserving case. Empty when absent/unparseable; multiple parents are retained."
          },
          "references": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Ordered References IDs without angle brackets, preserving case. Empty when absent/unparseable."
          },
          "delivery_id": {
            "type": "string",
            "pattern": "^[0-9a-f]{32}$",
            "description": "Revdoku delivery identity, matching email_delivery_id metadata and the original folder suffix. Stable on retries, independent of Message-ID. Copies retain the source identity; not a unique file/copy ID."
          },
          "thread_id": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^thr_[0-9a-f]{64}$",
            "description": "thr_ plus SHA-256 of thread_anchor_message_id. Best-effort header-derived grouping hint, not authoritative conversation membership or an access grant. Missing ancestry or reused IDs can split/merge hints. Scope lookups to accessible buckets."
          },
          "thread_id_source": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "references",
              "in_reply_to",
              "message_id",
              null
            ]
          },
          "thread_anchor_message_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "First References ID, otherwise the sole In-Reply-To ID, otherwise this message's ID if no parent is available. Null without an anchor or when multiple parents lack References."
          },
          "delivered_to": {
            "type": "string"
          },
          "received_at": {
            "type": "string",
            "format": "date-time"
          },
          "body_text": {
            "type": [
              "string",
              "null"
            ]
          },
          "body_status": {
            "type": "string",
            "enum": [
              "complete",
              "empty",
              "truncated",
              "unavailable"
            ]
          },
          "omitted_attachment_count": {
            "type": "integer",
            "minimum": 1
          },
          "attachments": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "path",
                "original_filename",
                "content_type",
                "size_bytes"
              ],
              "properties": {
                "path": {
                  "type": "string",
                  "description": "Relative to message folder."
                },
                "original_filename": {
                  "type": "string"
                },
                "content_type": {
                  "type": "string"
                },
                "size_bytes": {
                  "type": "integer",
                  "minimum": 0,
                  "format": "int64"
                },
                "origin": {
                  "type": "string",
                  "enum": [
                    "original",
                    "forwarder",
                    "forwarded_message",
                    "unspecified"
                  ],
                  "description": "For normalized forwards: inner attachment, member addition, attached source EML, or unknown inline-forward origin."
                }
              }
            }
          },
          "forwarding": {
            "$ref": "#/components/schemas/EmailForwardingContent"
          },
          "cc": {
            "type": [
              "string",
              "null"
            ],
            "description": "Decoded Cc header; use the corresponding parsed address array for individual addresses."
          },
          "reply_to": {
            "type": [
              "string",
              "null"
            ],
            "description": "Decoded Reply-To header; use the corresponding parsed address array for individual addresses."
          }
        }
      },
      "EmailSummary": {
        "type": "object",
        "properties": {
          "subject": {
            "type": [
              "string",
              "null"
            ]
          },
          "from_addresses": {
            "type": "array",
            "description": "Parsed From authors in header order, retaining multiple authors. Empty when absent/unparseable. Display names are not identity keys.",
            "items": {
              "$ref": "#/components/schemas/DecodedEmailAddress"
            }
          },
          "to_addresses": {
            "type": "array",
            "description": "Parsed To recipients in header order, with named groups flattened. Empty when absent/unparseable; not trusted delivery routing.",
            "items": {
              "$ref": "#/components/schemas/DecodedEmailAddress"
            }
          },
          "cc_addresses": {
            "type": "array",
            "description": "Parsed Cc recipients in header order, with named groups flattened. Empty when absent/unparseable.",
            "items": {
              "$ref": "#/components/schemas/DecodedEmailAddress"
            }
          },
          "reply_to_addresses": {
            "type": "array",
            "description": "Parsed Reply-To addresses in header order. Empty when absent/unparseable. Does not authorize sending a reply.",
            "items": {
              "$ref": "#/components/schemas/DecodedEmailAddress"
            }
          },
          "message_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Sender Message-ID without angle brackets, preserving case. Null when absent/unparseable/ambiguous; never the Revdoku delivery ID."
          },
          "in_reply_to": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Ordered parent Message-IDs without angle brackets, preserving case. Empty when absent/unparseable; multiple parents are retained."
          },
          "references": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Ordered References IDs without angle brackets, preserving case. Empty when absent/unparseable."
          },
          "delivered_to": {
            "type": "string"
          },
          "received_at": {
            "type": "string",
            "format": "date-time",
            "description": "Receipt time. For sent emails, the time Revdoku accepted the send."
          },
          "body_status": {
            "type": "string",
            "enum": [
              "complete",
              "empty",
              "truncated",
              "unavailable",
              "withheld"
            ]
          },
          "omitted_attachment_count": {
            "type": "integer",
            "minimum": 1
          },
          "id": {
            "type": "string",
            "pattern": "^eml_"
          },
          "conversation_id": {
            "type": "string",
            "pattern": "^eml_",
            "description": "Email ID that identifies the conversation. Replies are linked by email headers. Filter a list with conversation_id."
          },
          "direction": {
            "type": "string",
            "enum": [
              "received",
              "sent"
            ],
            "description": "received for incoming email; sent for email sent from this bucket."
          },
          "delivery": {
            "$ref": "#/components/schemas/EmailDelivery"
          },
          "labels": {
            "type": "array",
            "description": "Labels on the email files. When AI labels are on for the account, they add one built-in category label, such as Junk or Receipts, a few seconds after the email arrives, usually after the ticket event.",
            "items": {
              "$ref": "#/components/schemas/EmailLabel"
            }
          },
          "withheld": {
            "type": "boolean",
            "description": "True means Revdoku hides the email's content from API keys and MCP: the subject, display names, sender address (except its domain), body and attachments. If labels includes the Junk label, the email is junk: skip it. Downloads of the email and its files return EMAIL_WITHHELD, and a person can review it in the dashboard. Otherwise AI labels have not checked it yet: keep its ID and read it again with getEmail / get_email after a few seconds. The read returns 503 EMAIL_LABELING_PENDING with Retry-After until the label is ready (at most about one minute). Do not drop a pending email."
          },
          "file_id": {
            "type": "string",
            "pattern": "^df_",
            "description": "Included only with include_storage=true for file-browser integration."
          },
          "version_id": {
            "type": "string",
            "description": "Included only with include_storage=true for file-browser integration."
          },
          "attachment_count": {
            "type": "integer",
            "minimum": 0
          },
          "read": {
            "type": "boolean"
          },
          "read_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "read_by": {
            "type": [
              "object",
              "null"
            ]
          },
          "read_by_api_key": {
            "type": [
              "object",
              "null"
            ]
          },
          "files": {
            "type": "object",
            "properties": {
              "body_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "original_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "attachment_ids": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "directory": {
                "type": "string",
                "description": "Storage folder containing this email, without a trailing slash."
              }
            },
            "required": [
              "body_id",
              "original_id",
              "attachment_ids"
            ],
            "description": "Included only with include_storage=true for file-browser integration."
          },
          "forwarding": {
            "$ref": "#/components/schemas/EmailForwarding"
          }
        },
        "required": [
          "id",
          "conversation_id",
          "direction",
          "received_at",
          "attachment_count",
          "labels",
          "withheld",
          "read",
          "read_at",
          "read_by",
          "read_by_api_key"
        ]
      },
      "FileActor": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          }
        }
      },
      "FileKey": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "token_type": {
            "type": "string"
          }
        }
      },
      "FileVersionReason": {
        "type": "object",
        "properties": {
          "version_id": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          },
          "created_by_id": {
            "type": "string"
          },
          "version_number": {
            "type": "integer",
            "format": "int64"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "UploadBlob": {
        "type": "object",
        "properties": {
          "filename": {
            "type": "string"
          },
          "byte_size": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "checksum": {
            "type": "string"
          },
          "content_type": {
            "type": "string"
          },
          "sha256": {
            "type": "string"
          },
          "purpose": {
            "type": "string",
            "enum": [
              "bucket_file"
            ]
          }
        },
        "required": [
          "filename",
          "byte_size",
          "checksum",
          "content_type",
          "sha256",
          "purpose"
        ]
      },
      "StorageUpload": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          },
          "headers": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          }
        },
        "required": [
          "url",
          "headers"
        ]
      },
      "FileUploadSkip": {
        "type": "object",
        "properties": {
          "path": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "input_index": {
            "type": "integer"
          },
          "details": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "FileVersion": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "file_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "mime_type": {
            "type": "string"
          },
          "sha256": {
            "type": "string"
          },
          "reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_by_system": {
            "type": "string"
          },
          "deleted": {
            "type": "boolean",
            "description": "True for the version that records a deletion."
          },
          "ready": {
            "type": "boolean"
          },
          "has_text": {
            "type": "boolean"
          },
          "version_number": {
            "type": "integer",
            "format": "int64"
          },
          "byte_size": {
            "type": "integer",
            "format": "int64"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "created_by": {
            "$ref": "#/components/schemas/FileActor"
          },
          "updated_by": {
            "$ref": "#/components/schemas/FileActor"
          },
          "created_by_agent": {
            "type": "object",
            "additionalProperties": true
          },
          "updated_by_agent": {
            "type": "object",
            "additionalProperties": true
          },
          "created_by_api_key": {
            "type": "object",
            "additionalProperties": true
          },
          "updated_by_api_key": {
            "type": "object",
            "additionalProperties": true
          },
          "read": {
            "type": "boolean"
          },
          "read_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "read_by": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/FileActor"
              },
              {
                "type": "null"
              }
            ]
          },
          "read_by_api_key": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/FileKey"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "file_id",
          "version_number"
        ]
      },
      "BucketFile": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "bucket_id": {
            "type": "string",
            "pattern": "^bkt_"
          },
          "basename": {
            "type": "string"
          },
          "path": {
            "type": "string"
          },
          "role": {
            "type": "string"
          },
          "created_by_system": {
            "type": "string"
          },
          "deleted": {
            "type": "boolean"
          },
          "version_reasons": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FileVersionReason"
            }
          },
          "lock": {
            "type": "object",
            "additionalProperties": true
          },
          "current_file_version": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/FileVersion"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_by": {
            "$ref": "#/components/schemas/FileActor"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "deleted_at": {
            "type": "string",
            "format": "date-time"
          },
          "created_by_agent": {
            "type": "object",
            "additionalProperties": true
          },
          "updated_by_agent": {
            "type": "object",
            "additionalProperties": true
          },
          "created_by_api_key": {
            "type": "object",
            "additionalProperties": true
          },
          "updated_by_api_key": {
            "type": "object",
            "additionalProperties": true
          },
          "read": {
            "type": "boolean"
          },
          "read_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "read_by": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/FileActor"
              },
              {
                "type": "null"
              }
            ]
          },
          "read_by_api_key": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/FileKey"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "path"
        ]
      },
      "FileList": {
        "type": "object",
        "required": [
          "files",
          "pagination"
        ],
        "properties": {
          "files": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BucketFile"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "FileVersionList": {
        "type": "object",
        "required": [
          "versions",
          "pagination"
        ],
        "properties": {
          "versions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FileVersion"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "FileDownload": {
        "type": "object",
        "required": [
          "download",
          "version"
        ],
        "properties": {
          "download": {
            "$ref": "#/components/schemas/Download"
          },
          "version": {
            "$ref": "#/components/schemas/FileVersion"
          },
          "previously_read": {
            "type": "boolean",
            "description": "Read state before this request, when tracking succeeded."
          }
        }
      },
      "PrepareFileUploadRequest": {
        "type": "object",
        "required": [
          "path",
          "blob"
        ],
        "properties": {
          "path": {
            "type": "string",
            "description": "Destination path in the bucket. Paths under _mailbox/ return MAILBOX_PATH_READ_ONLY; paths under _agents/ and _revdoku/ return RESERVED_PATH."
          },
          "existing_file_policy": {
            "type": "string",
            "enum": [
              "replace",
              "skip"
            ],
            "default": "replace",
            "description": "skip returns the existing file without an upload when the path exists."
          },
          "blob": {
            "$ref": "#/components/schemas/UploadBlob"
          },
          "account_id": {
            "type": "string"
          },
          "reason": {
            "$ref": "#/components/schemas/ActionReason"
          }
        }
      },
      "PreparedFileUpload": {
        "type": "object",
        "properties": {
          "signed_id": {
            "type": "string"
          },
          "filename": {
            "type": "string"
          },
          "byte_size": {
            "type": "integer",
            "format": "int64"
          },
          "checksum": {
            "type": "string"
          },
          "content_type": {
            "type": "string"
          },
          "direct_upload": {
            "$ref": "#/components/schemas/StorageUpload"
          },
          "file": {
            "$ref": "#/components/schemas/BucketFile"
          },
          "version": {
            "$ref": "#/components/schemas/FileVersion"
          },
          "skipped": {
            "type": "boolean"
          },
          "duplicate": {
            "type": "boolean"
          },
          "reason": {
            "type": "string"
          },
          "details": {
            "type": "object",
            "additionalProperties": true
          }
        },
        "description": "A new upload returns signed_id and direct_upload. Identical content returns skipped=true, duplicate=true, file and version without a storage upload."
      },
      "SaveUploadedFileRequest": {
        "type": "object",
        "required": [
          "path",
          "signed_blob_id"
        ],
        "properties": {
          "path": {
            "type": "string",
            "description": "Destination path. An existing path receives a new version. Paths under _mailbox/ return MAILBOX_PATH_READ_ONLY; paths under _agents/ and _revdoku/ return RESERVED_PATH."
          },
          "signed_blob_id": {
            "type": "string",
            "description": "data.signed_id from POST /v1/buckets/{bucket_id}/uploads."
          },
          "name": {
            "type": "string",
            "description": "Display name; defaults to the last path segment."
          },
          "role": {
            "type": "string",
            "enum": [
              "source",
              "reference",
              "generated",
              "agent_output",
              "export",
              "artifact"
            ],
            "default": "source"
          },
          "existing_file_policy": {
            "type": "string",
            "enum": [
              "replace",
              "skip"
            ],
            "default": "replace"
          },
          "expected_bucket_version": {
            "type": "string",
            "description": "Bucket version_id from your last read. A different current version returns BUCKET_VERSION_CONFLICT and saves nothing."
          },
          "account_id": {
            "type": "string"
          },
          "reason": {
            "$ref": "#/components/schemas/ActionReason"
          }
        }
      },
      "SavedFile": {
        "type": "object",
        "properties": {
          "file": {
            "$ref": "#/components/schemas/BucketFile"
          },
          "version": {
            "$ref": "#/components/schemas/FileVersion"
          },
          "created": {
            "type": "boolean"
          },
          "skipped": {
            "$ref": "#/components/schemas/FileUploadSkip"
          },
          "duplicate": {
            "type": "boolean"
          }
        },
        "required": [
          "file",
          "version",
          "created"
        ]
      },
      "AppendTextResult": {
        "type": "object",
        "required": [
          "file",
          "version",
          "path",
          "appended",
          "appended_bytes",
          "newline_inserted"
        ],
        "properties": {
          "file": {
            "$ref": "#/components/schemas/BucketFile"
          },
          "version": {
            "$ref": "#/components/schemas/FileVersion"
          },
          "path": {
            "type": "string"
          },
          "appended": {
            "type": "boolean",
            "const": true
          },
          "appended_bytes": {
            "type": "integer",
            "minimum": 0
          },
          "newline_inserted": {
            "type": "boolean"
          }
        }
      },
      "PathOperationResult": {
        "type": "object",
        "required": [
          "operation",
          "skipped",
          "path"
        ],
        "properties": {
          "operation": {
            "type": "string",
            "enum": [
              "rename",
              "move",
              "copy"
            ]
          },
          "skipped": {
            "type": "boolean",
            "description": "True when the file already had the requested path."
          },
          "old_path": {
            "type": "string"
          },
          "path": {
            "type": "string"
          },
          "source_bucket_id": {
            "type": "string"
          },
          "target_bucket_id": {
            "type": "string"
          },
          "source_file": {
            "$ref": "#/components/schemas/BucketFile"
          },
          "file": {
            "$ref": "#/components/schemas/BucketFile"
          },
          "version": {
            "$ref": "#/components/schemas/FileVersion"
          }
        }
      },
      "RestoredFileVersion": {
        "type": "object",
        "required": [
          "file",
          "version",
          "restored_from"
        ],
        "properties": {
          "file": {
            "$ref": "#/components/schemas/BucketFile"
          },
          "version": {
            "$ref": "#/components/schemas/FileVersion"
          },
          "restored_from": {
            "$ref": "#/components/schemas/FileVersion"
          }
        }
      },
      "CodeRequested": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "expires_in_seconds": {
            "type": "integer"
          },
          "fallback_url": {
            "type": "string",
            "format": "uri"
          },
          "hint": {
            "type": "string"
          }
        }
      },
      "AgentConnection": {
        "type": "object",
        "description": "A new API key for an AI agent or the CLI. Store api_key securely; it is shown only once.",
        "required": [
          "api_key",
          "account_id",
          "scope"
        ],
        "properties": {
          "api_key": {
            "type": "string"
          },
          "account_id": {
            "type": "string"
          },
          "account_name": {
            "type": "string"
          },
          "scope": {
            "type": "string",
            "enum": [
              "bucket_read",
              "bucket_write",
              "bucket_admin"
            ]
          },
          "bucket_access": {
            "type": "string",
            "enum": [
              "all",
              "selected"
            ]
          },
          "bucket_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "bucket_permissions": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "account_connection_limits": {
            "type": "object",
            "additionalProperties": true
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "manage_access": {
            "type": "object",
            "additionalProperties": true
          },
          "buckets": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "guidance": {
            "type": "string"
          }
        }
      },
      "BrowserLink": {
        "type": "object",
        "required": [
          "url",
          "path"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Dashboard link. The user signs in normally; the link grants nothing."
          },
          "path": {
            "type": "string"
          },
          "single_use": {
            "type": "boolean"
          },
          "requires_login": {
            "type": "boolean"
          },
          "redirect_path": {
            "type": "string"
          }
        }
      },
      "UploadSessionFile": {
        "type": "object",
        "required": [
          "path",
          "byte_size",
          "content_type",
          "checksum",
          "sha256"
        ],
        "properties": {
          "path": {
            "type": "string",
            "description": "Destination path in the bucket. Paths under _mailbox/ return MAILBOX_PATH_READ_ONLY; paths under _agents/ and _revdoku/ return RESERVED_PATH."
          },
          "byte_size": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "content_type": {
            "type": "string"
          },
          "checksum": {
            "type": "string",
            "description": "Base64-encoded MD5 of the bytes."
          },
          "sha256": {
            "type": "string",
            "description": "Hex SHA-256 of the bytes."
          }
        }
      },
      "UploadSessionUpload": {
        "type": "object",
        "required": [
          "path",
          "upload"
        ],
        "properties": {
          "input_index": {
            "type": "integer"
          },
          "path": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "signed_blob_id": {
            "type": "string"
          },
          "upload": {
            "$ref": "#/components/schemas/StorageUpload"
          }
        },
        "description": "PUT the bytes of path to upload.url with exactly upload.headers and no API key."
      },
      "UploadSession": {
        "type": "object",
        "required": [
          "id",
          "bucket_id",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^bus_"
          },
          "bucket_id": {
            "type": "string",
            "pattern": "^bkt_"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "finalized",
              "expired",
              "failed"
            ],
            "description": "pending accepts uploads. failed means canceled; its unsaved files were discarded."
          },
          "base_bucket_version_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Bucket version when the session started."
          },
          "target_bucket_version_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Bucket version created by the final save."
          },
          "uploads_expire_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Unsaved uploads are discarded after this time."
          },
          "session_closed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "files_count": {
            "type": "integer",
            "minimum": 0
          },
          "pending_files_count": {
            "type": "integer",
            "minimum": 0
          },
          "uploaded_files_count": {
            "type": "integer",
            "minimum": 0
          },
          "finalized_files_count": {
            "type": "integer",
            "minimum": 0
          },
          "skipped_files_count": {
            "type": "integer",
            "minimum": 0
          },
          "skipped_code_counts": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            },
            "description": "Skipped files per skip code."
          },
          "failed_files_count": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "UploadedFile": {
        "type": "object",
        "required": [
          "path",
          "file",
          "version",
          "created"
        ],
        "properties": {
          "input_index": {
            "type": "integer"
          },
          "path": {
            "type": "string"
          },
          "file": {
            "$ref": "#/components/schemas/BucketFile"
          },
          "version": {
            "$ref": "#/components/schemas/FileVersion"
          },
          "created": {
            "type": "boolean",
            "description": "False when the path received a new version."
          }
        }
      },
      "UploadSessionResult": {
        "type": "object",
        "required": [
          "bucket_upload_session",
          "uploaded",
          "uploaded_count",
          "skipped",
          "skipped_count"
        ],
        "properties": {
          "bucket_upload_session": {
            "$ref": "#/components/schemas/UploadSession"
          },
          "uploads": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UploadSessionUpload"
            },
            "description": "Create and uploads only: storage targets for the files that need bytes."
          },
          "uploaded": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UploadedFile"
            },
            "description": "Files saved by this request (at most 250)."
          },
          "uploaded_count": {
            "type": "integer",
            "minimum": 0
          },
          "uploaded_truncated": {
            "type": "boolean"
          },
          "created_count": {
            "type": "integer",
            "minimum": 0
          },
          "updated_count": {
            "type": "integer",
            "minimum": 0
          },
          "skipped": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FileUploadSkip"
            },
            "description": "Files left unchanged, for example identical content (DUPLICATE_FILE_VERSION)."
          },
          "skipped_count": {
            "type": "integer",
            "minimum": 0
          },
          "skipped_truncated": {
            "type": "boolean"
          },
          "finalize_pending": {
            "type": "boolean",
            "description": "Finalize only: true when more files remain. Call finalize again after Retry-After."
          },
          "remaining_files_count": {
            "type": "integer",
            "minimum": 0
          },
          "message": {
            "type": "string"
          }
        }
      },
      "ActionRequest": {
        "type": "object",
        "description": "Optional account selection and reason for an action without other input.",
        "properties": {
          "account_id": {
            "type": "string",
            "description": "Select another granted account for this request."
          },
          "reason": {
            "$ref": "#/components/schemas/ActionReason"
          }
        }
      },
      "Publication": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "bucket_id",
          "url",
          "preview",
          "publish_state",
          "live",
          "access_mode",
          "password_configured",
          "publish_error",
          "expires_at",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Publication ID."
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "description": "The site address."
          },
          "preview": {
            "type": "boolean",
            "description": "True for a 24-hour preview."
          },
          "publish_state": {
            "type": "string",
            "enum": [
              "ready",
              "queued",
              "processing",
              "failed",
              "unpublishing"
            ],
            "description": "Build state. A publish runs in the background: poll until ready or failed."
          },
          "live": {
            "type": "boolean",
            "description": "True while the site serves visitors."
          },
          "access_mode": {
            "type": "string",
            "enum": [
              "public",
              "password",
              "require_email"
            ],
            "description": "Who can open the site."
          },
          "password_configured": {
            "type": "boolean",
            "description": "True when a password protects the site."
          },
          "publish_error": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why the last build failed."
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When a preview stops serving."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "bucket_id": {
            "type": "string",
            "description": "The bucket whose files the site publishes."
          }
        },
        "description": "A bucket's published site, or its 24-hour preview."
      },
      "PublishRequest": {
        "type": "object",
        "properties": {
          "access_mode": {
            "type": "string",
            "enum": [
              "public",
              "password",
              "require_email"
            ],
            "description": "Who can open the site. Omit to keep the current setting. Sites are public: password and require_email return 422 PUBLICATION_ACCESS_MODE_INVALID unless Revdoku turned on private sites for the account."
          },
          "password": {
            "type": "string",
            "writeOnly": true,
            "minLength": 8,
            "maxLength": 128,
            "description": "Password for access_mode password, 8 to 128 characters. Omit to generate one."
          },
          "reason": {
            "type": "string",
            "maxLength": 2000,
            "description": "Why you publish, for the activity log."
          }
        }
      },
      "PreviewRequest": {
        "type": "object",
        "properties": {
          "access_mode": {
            "type": "string",
            "enum": [
              "public",
              "password",
              "require_email"
            ],
            "description": "Who can open the site. Omit to keep the current setting. Sites are public: password and require_email return 422 PUBLICATION_ACCESS_MODE_INVALID unless Revdoku turned on private sites for the account."
          },
          "password": {
            "type": "string",
            "writeOnly": true,
            "minLength": 8,
            "maxLength": 128,
            "description": "Password for access_mode password, 8 to 128 characters. Omit to generate one."
          },
          "reason": {
            "type": "string",
            "maxLength": 2000,
            "description": "Why you publish, for the activity log."
          },
          "branch": {
            "type": "string",
            "description": "A branch of the connected GitHub repository, other than the linked branch (see listGithubBranches). The preview then shows that branch, as after a push to it, with the site's access. Needs a live site. Omit to preview the bucket's current files."
          }
        }
      },
      "GithubSyncError": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "code",
          "message"
        ],
        "description": "Why a sync or a publish after a sync failed: a stable code and one readable sentence.",
        "properties": {
          "code": {
            "type": "string",
            "description": "For example REMOTE_BRANCH_GONE, GITHUB_REPO_ACCESS_REMOVED, GITHUB_APP_UNINSTALLED or GITHUB_SYNC_FAILED."
          },
          "message": {
            "type": "string"
          }
        }
      },
      "GithubSync": {
        "type": "object",
        "additionalProperties": false,
        "description": "The GitHub repository of a bucket. The bucket's files are a copy of one branch, or of one folder of it.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Link ID."
          },
          "bucket_id": {
            "type": "string"
          },
          "installation_id": {
            "type": "integer",
            "description": "The connected GitHub account (Revdoku GitHub App installation) that reads the repository."
          },
          "repo_owner": {
            "type": "string",
            "description": "The GitHub account or organization that owns the repository."
          },
          "repo_name": {
            "type": "string"
          },
          "repo_full_name": {
            "type": "string",
            "description": "owner/name."
          },
          "repository_url": {
            "type": "string",
            "format": "uri"
          },
          "branch": {
            "type": "string"
          },
          "repo_path": {
            "type": [
              "string",
              "null"
            ],
            "description": "The repository folder that is the bucket root. Null: the whole repository."
          },
          "sync_state": {
            "type": "string",
            "enum": [
              "idle",
              "syncing",
              "waiting_locked",
              "error",
              "disconnected"
            ],
            "description": "idle: nothing runs. syncing: a sync runs. waiting_locked: the bucket is locked and the sync tries again later. error: see last_error and next_retry_at. disconnected: the repository is no longer connected."
          },
          "last_error": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/GithubSyncError"
              },
              {
                "type": "null"
              }
            ],
            "description": "Why the last sync failed or waits, or why GitHub disconnected the repository."
          },
          "next_retry_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When a failed sync tries again. Null after the last try: sync again after the cause is fixed."
          },
          "last_synced_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the last sync finished. Null until the first copy is done."
          },
          "last_synced_commit_sha": {
            "type": [
              "string",
              "null"
            ],
            "description": "The commit of the branch that the files show."
          },
          "last_synced_commit_message": {
            "type": [
              "string",
              "null"
            ]
          },
          "auto_publish": {
            "type": "boolean",
            "description": "The site publishes again after each sync. The first publish is publishBucket."
          },
          "push_revdoku_edits": {
            "type": "boolean",
            "description": "Edits made in Revdoku can go to GitHub. False: the files are a read-only copy of the repository."
          },
          "auto_commit": {
            "type": "boolean",
            "description": "Each sync commits the edits made in Revdoku to the branch. False: they wait in pending_changes until a person publishes them in the dashboard."
          },
          "pending_count": {
            "type": "integer",
            "description": "Edits made in Revdoku that are not on the branch."
          },
          "pending_changes": {
            "type": "array",
            "description": "The first 200 of these edits.",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "path",
                "status"
              ],
              "properties": {
                "path": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "description": "For example added, modified or deleted."
                }
              }
            }
          },
          "pull_request": {
            "anyOf": [
              {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "number",
                  "branch",
                  "url"
                ],
                "description": "Revdoku's open pull request with edits made in Revdoku.",
                "properties": {
                  "number": {
                    "type": [
                      "integer",
                      "null"
                    ],
                    "description": "Null until GitHub accepted the pull request."
                  },
                  "branch": {
                    "type": "string"
                  },
                  "url": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "uri"
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "skipped_files": {
            "type": "array",
            "description": "Repository files that the last sync left out, for example files that are too large or stored in Git LFS.",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "path",
                "code",
                "reason"
              ],
              "properties": {
                "path": {
                  "type": "string"
                },
                "code": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "reason": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              }
            }
          },
          "auto_publish_error": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/GithubSyncError"
              },
              {
                "type": "null"
              }
            ],
            "description": "Why the site was not published again after the last sync."
          },
          "dashboard_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "The bucket's GitHub page in the dashboard. It grants no access."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "bucket_id",
          "installation_id",
          "repo_owner",
          "repo_name",
          "repo_full_name",
          "repository_url",
          "branch",
          "repo_path",
          "sync_state",
          "last_error",
          "next_retry_at",
          "last_synced_at",
          "last_synced_commit_sha",
          "last_synced_commit_message",
          "auto_publish",
          "push_revdoku_edits",
          "auto_commit",
          "pending_count",
          "pending_changes",
          "pull_request",
          "skipped_files",
          "auto_publish_error",
          "dashboard_url",
          "created_at",
          "updated_at"
        ]
      },
      "GithubInstallation": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "installation_id",
          "settings_url"
        ],
        "description": "A GitHub account or organization where a person installed the Revdoku GitHub App for this account.",
        "properties": {
          "installation_id": {
            "type": "integer",
            "description": "Pass it to listGithubRepositories, and optionally to connectGithubRepository."
          },
          "github_account_login": {
            "type": "string"
          },
          "github_account_type": {
            "type": "string",
            "description": "User or Organization."
          },
          "settings_url": {
            "type": "string",
            "format": "uri",
            "description": "The installation's page on GitHub, where its owner chooses the repositories that Revdoku can read."
          },
          "repository_selection": {
            "type": "string",
            "enum": [
              "all",
              "selected"
            ],
            "description": "all: every repository of the account. selected: only the repositories that its owner chose."
          }
        }
      },
      "GithubRepository": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "owner",
          "name",
          "full_name",
          "default_branch",
          "private",
          "archived"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "description": "GitHub repository ID."
          },
          "owner": {
            "type": "string",
            "description": "Pass as repo_owner to connectGithubRepository."
          },
          "name": {
            "type": "string",
            "description": "Pass as repo_name."
          },
          "full_name": {
            "type": "string"
          },
          "default_branch": {
            "type": "string"
          },
          "private": {
            "type": "boolean"
          },
          "archived": {
            "type": "boolean"
          },
          "html_url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "GithubSetupLink": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "install_url",
          "authorization_url",
          "expires_at",
          "dashboard_url"
        ],
        "description": "Links for a person's step on GitHub. Only the person who owns this key or AI connection can finish it, signed in to Revdoku. Never ask for GitHub passwords or tokens.",
        "properties": {
          "install_url": {
            "type": "string",
            "format": "uri",
            "description": "Installs the Revdoku GitHub App on a GitHub account or organization and connects it. On GitHub the person chooses the repositories."
          },
          "authorization_url": {
            "type": "string",
            "format": "uri",
            "description": "For a GitHub account where the App is already installed. After it, the person selects Connect on the bucket's GitHub page."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "The links work for 30 minutes."
          },
          "dashboard_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "The bucket's GitHub page in the dashboard. The person sees the result there, and another owner or administrator can add the GitHub account there."
          }
        }
      },
      "GithubConnect": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "repo_owner",
          "repo_name"
        ],
        "properties": {
          "repo_owner": {
            "type": "string",
            "description": "The GitHub account or organization that owns the repository."
          },
          "repo_name": {
            "type": "string",
            "maxLength": 100
          },
          "branch": {
            "type": "string",
            "description": "The branch to copy. Default: the repository's default branch."
          },
          "repo_path": {
            "type": "string",
            "description": "One folder of the repository as the bucket root, such as docs. Default: the whole repository."
          },
          "installation_id": {
            "type": "integer",
            "minimum": 1,
            "description": "The connected GitHub account that reads the repository. Default: the connected account of repo_owner."
          },
          "push_revdoku_edits": {
            "type": "boolean",
            "description": "False makes the files a read-only copy of the repository. Default: true."
          }
        }
      },
      "GithubSyncSettings": {
        "type": "object",
        "additionalProperties": false,
        "minProperties": 1,
        "properties": {
          "auto_publish": {
            "type": "boolean",
            "description": "Publish the site again after each sync."
          },
          "push_revdoku_edits": {
            "type": "boolean",
            "description": "False makes the files a read-only copy of the repository."
          },
          "auto_commit": {
            "type": "boolean",
            "description": "True commits the edits made in Revdoku to the branch at each sync. False keeps them for a person to publish in the dashboard."
          }
        }
      },
      "LockRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "message"
        ],
        "properties": {
          "message": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500,
            "description": "Why you lock it. Shown to others."
          },
          "paths": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100,
            "items": {
              "type": "string",
              "minLength": 1
            },
            "description": "File paths in the bucket. Omit for the whole bucket. Paths under _mailbox/ return MAILBOX_PATH_READ_ONLY; paths under _agents/ and _revdoku/ return RESERVED_PATH."
          },
          "duration_seconds": {
            "type": "integer",
            "minimum": 1,
            "maximum": 900,
            "default": 900,
            "description": "Lock length in seconds, at most 900. The lock expires by itself."
          },
          "account_id": {
            "type": "string",
            "description": "Select another granted account for this request."
          },
          "reason": {
            "$ref": "#/components/schemas/ActionReason"
          }
        }
      },
      "UnlockRequest": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "paths": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100,
            "items": {
              "type": "string",
              "minLength": 1
            },
            "description": "File paths to unlock. Omit to unlock the whole bucket."
          },
          "account_id": {
            "type": "string",
            "description": "Select another granted account for this request."
          },
          "reason": {
            "$ref": "#/components/schemas/ActionReason"
          }
        }
      },
      "Ticket": {
        "type": "object",
        "required": [
          "id",
          "number",
          "status",
          "subject",
          "channel",
          "requester",
          "labels",
          "message_count",
          "unread_count",
          "created_at",
          "updated_at",
          "last_message_at",
          "solved_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^tkt_",
            "description": "Ticket ID for API calls."
          },
          "number": {
            "type": "integer",
            "minimum": 1,
            "description": "Ticket number in the bucket. Replies end their subject with [#number]."
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "solved"
            ],
            "description": "A new message from the requester reopens a solved ticket."
          },
          "subject": {
            "type": [
              "string",
              "null"
            ],
            "description": "Subject of the first message. Null while that message is withheld."
          },
          "channel": {
            "type": "string",
            "enum": [
              "email",
              "chat",
              "feedback"
            ],
            "description": "Where the ticket started: an email, a message left on the docs site, or anonymous page feedback."
          },
          "requester": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/DecodedEmailAddress"
              },
              {
                "type": "null"
              }
            ],
            "description": "The person who wrote. Null for anonymous feedback, which nobody can reply to."
          },
          "labels": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailLabel"
            },
            "description": "Labels of the ticket's messages."
          },
          "message_count": {
            "type": "integer",
            "minimum": 0
          },
          "unread_count": {
            "type": "integer",
            "minimum": 0,
            "description": "Received messages that nobody has read."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last activity: the newest message or a status change."
          },
          "last_message_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "solved_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "TicketList": {
        "type": "object",
        "required": [
          "tickets",
          "pagination"
        ],
        "properties": {
          "tickets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Ticket"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "TicketMessage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/EmailSummary"
          },
          {
            "type": "object",
            "required": [
              "ticket_id",
              "channel"
            ],
            "properties": {
              "ticket_id": {
                "type": "string",
                "pattern": "^tkt_"
              },
              "channel": {
                "type": "string",
                "enum": [
                  "email",
                  "chat",
                  "feedback"
                ]
              },
              "body_text": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "body_status": {
                "type": "string",
                "enum": [
                  "complete",
                  "empty",
                  "truncated",
                  "unavailable",
                  "withheld"
                ]
              },
              "attachments": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/EmailAttachment"
                }
              },
              "forwarding": {
                "$ref": "#/components/schemas/EmailForwardingContent"
              }
            }
          }
        ],
        "description": "One message of a ticket: an email of its conversation. Reads include body_text, body_status and attachments. Junk email and new email that AI labels still check are withheld."
      },
      "TicketMessageList": {
        "type": "object",
        "required": [
          "messages",
          "pagination"
        ],
        "properties": {
          "messages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TicketMessage"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "TicketReplyRequest": {
        "type": "object",
        "required": [
          "text"
        ],
        "properties": {
          "subject": {
            "type": "string",
            "maxLength": 255,
            "description": "Defaults to \"Re: \" plus the original subject."
          },
          "text": {
            "type": "string",
            "minLength": 1,
            "description": "Plain-text body, up to 1 MiB."
          },
          "html": {
            "type": "string",
            "description": "Optional HTML body, up to 1 MiB."
          },
          "attachment_ids": {
            "type": "array",
            "maxItems": 10,
            "items": {
              "type": "string",
              "pattern": "^df_"
            },
            "description": "Existing file IDs in this bucket to attach."
          },
          "account_id": {
            "type": "string"
          },
          "reason": {
            "$ref": "#/components/schemas/ActionReason"
          }
        },
        "description": "A reply to the ticket's requester. There is no to, cc or in_reply_to: they return 422 INVALID_ARGUMENT."
      },
      "TicketUpdateRequest": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "open",
              "solved"
            ]
          },
          "add_labels": {
            "type": "array",
            "maxItems": 10,
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "description": "Label names to add to the ticket's first message. A new name creates the label."
          },
          "remove_labels": {
            "type": "array",
            "maxItems": 10,
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "description": "Label names to remove from every message of the ticket."
          },
          "account_id": {
            "type": "string",
            "description": "Select another granted account for this request."
          },
          "reason": {
            "$ref": "#/components/schemas/ActionReason"
          }
        }
      }
    },
    "parameters": {
      "AccountId": {
        "name": "account_id",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string"
        },
        "description": "Select another granted account for this request. Omit to use the credential default. In JSON bodies, send account_id as a body field instead."
      },
      "Reason": {
        "name": "reason",
        "in": "query",
        "required": false,
        "schema": {
          "$ref": "#/components/schemas/ActionReason"
        }
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 200,
          "default": 50
        }
      },
      "Cursor": {
        "name": "cursor",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string"
        },
        "description": "pagination.next_cursor from the previous page."
      },
      "BucketId": {
        "name": "bucket_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "pattern": "^bkt_"
        }
      },
      "FileId": {
        "name": "file_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "pattern": "^df_"
        }
      },
      "VersionId": {
        "name": "version_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "AttachmentId": {
        "name": "attachment_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "pattern": "^df_"
        }
      },
      "AccountPathId": {
        "name": "account_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "pattern": "^acct_"
        },
        "description": "Granted account to read."
      },
      "IncludeStorage": {
        "name": "include_storage",
        "in": "query",
        "required": false,
        "schema": {
          "type": "boolean",
          "default": false
        },
        "description": "Include backing file IDs for file-browser integrations."
      },
      "InstallationId": {
        "name": "installation_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "integer",
          "minimum": 1
        },
        "description": "installation_id of a connected GitHub account."
      },
      "TicketId": {
        "name": "ticket_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "pattern": "^tkt_"
        }
      },
      "MessageId": {
        "name": "message_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "pattern": "^eml_"
        }
      }
    },
    "responses": {
      "Error": {
        "description": "Request failed. See error.code. Any 429 or 503 response with Retry-After (for example 503 EMAIL_LABELING_PENDING or 503 EMAIL_INDEX_BUILDING): wait that many seconds, then try the request again. 429 EMAIL_SEND_RATE_LIMITED has no Retry-After. Never retry EMAIL_LOOP_DETECTED.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "LockResult": {
        "description": "Success: the bucket's lock, or the listed files with their locks.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "success",
                "data"
              ],
              "properties": {
                "success": {
                  "type": "boolean",
                  "const": true
                },
                "data": {
                  "type": "object",
                  "properties": {
                    "lock": {
                      "$ref": "#/components/schemas/BucketLock"
                    },
                    "files": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BucketFile"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
