{
  "openapi": "3.1.0",
  "info": {
    "title": "Cloudraw API",
    "version": "0.1.0",
    "summary": "Automate your Cloudraw workspace: people, devices, connectors, apps, access rules, audit and alerts.",
    "description": "The Cloudraw API is a JSON over HTTPS API. Every call is scoped to one workspace (`/v0/tenants/{tenant_id}/…`) and authenticated with a workspace API token (`Authorization: Bearer crw_…`). Errors are RFC 9457 problem details with a stable `code`. See the guides at https://cdapi.cloudraw.com/docs/api for getting started, authentication, errors, rate limits, pagination, idempotency, webhooks and the versioning policy.",
    "contact": {
      "name": "Cloudraw",
      "url": "https://cloudraw.com"
    },
    "license": {
      "name": "Proprietary. Use of the API is subject to your Cloudraw agreement."
    }
  },
  "servers": [
    {
      "url": "https://cdapi.cloudraw.com",
      "description": "Cloudraw API"
    }
  ],
  "security": [
    {
      "apiToken": []
    }
  ],
  "tags": [
    {
      "name": "Workspace",
      "description": "Your workspace record: name, plan limits and usage."
    },
    {
      "name": "People",
      "description": "The people who may use Cloudraw: invite, update, suspend, quarantine and remove them."
    },
    {
      "name": "Groups",
      "description": "Groups of people. Access rules and apps are usually granted to groups."
    },
    {
      "name": "Devices",
      "description": "Computers and phones running Cloudraw Connect: health, trust, quarantine."
    },
    {
      "name": "Enrollments",
      "description": "Enrollment codes that add a device or a connector to the workspace."
    },
    {
      "name": "Connectors",
      "description": "Connectors run in your network and publish its apps to Cloudraw. Install, monitor and update them."
    },
    {
      "name": "Connector updates",
      "description": "Update a connector now, pause or resume its automatic updates, and the workspace update policy."
    },
    {
      "name": "Apps",
      "description": "Apps (connections): a host and port behind a connector, published to people."
    },
    {
      "name": "Private networks",
      "description": "Whole subnets behind a connector, reachable from Cloudraw Connect."
    },
    {
      "name": "Access rules",
      "description": "Who may reach which app, from which device, under which conditions."
    },
    {
      "name": "Device trust",
      "description": "Trust rules and device-health (posture) profiles that decide whether a device is trusted."
    },
    {
      "name": "Just-in-time access",
      "description": "Requests for temporary access, their approval, and active grants."
    },
    {
      "name": "Sessions",
      "description": "Live sessions to your apps; end one."
    },
    {
      "name": "Audit log",
      "description": "Every change and sign-in in the workspace, tamper-evident (hash chained). Read, export, verify."
    },
    {
      "name": "Alerts",
      "description": "Alerts raised in the workspace and security events; acknowledge, resolve, dismiss."
    },
    {
      "name": "Webhooks",
      "description": "Signed HTTPS callbacks for alerts and events. See the Webhooks guide for signature verification."
    },
    {
      "name": "Log streaming",
      "description": "Stream the audit log and alerts to your SIEM."
    },
    {
      "name": "Support",
      "description": "Your support cases: summary and status."
    },
    {
      "name": "Dashboard tiles",
      "description": "The numbers on the dashboard: which tiles exist and their current values."
    },
    {
      "name": "Reports",
      "description": "Protection status of the workspace and the monthly customer report."
    }
  ],
  "x-tagGroups": [
    {
      "name": "Workspace",
      "tags": [
        "Workspace"
      ]
    },
    {
      "name": "Identity",
      "tags": [
        "People",
        "Groups"
      ]
    },
    {
      "name": "Devices",
      "tags": [
        "Devices",
        "Enrollments"
      ]
    },
    {
      "name": "Network",
      "tags": [
        "Connectors",
        "Connector updates",
        "Apps",
        "Private networks"
      ]
    },
    {
      "name": "Access control",
      "tags": [
        "Access rules",
        "Device trust",
        "Just-in-time access"
      ]
    },
    {
      "name": "Activity",
      "tags": [
        "Sessions",
        "Audit log"
      ]
    },
    {
      "name": "Alerts & integrations",
      "tags": [
        "Alerts",
        "Webhooks",
        "Log streaming"
      ]
    },
    {
      "name": "Support & reports",
      "tags": [
        "Support",
        "Dashboard tiles",
        "Reports"
      ]
    }
  ],
  "paths": {
    "/v0/tenants/{tenant_id}": {
      "get": {
        "tags": [
          "Workspace"
        ],
        "operationId": "getWorkspace",
        "summary": "Get the workspace",
        "description": "Returns your workspace: its name, plan limits, current usage and provisioning status. A cheap call that is handy as a token check.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "responses": {
          "200": {
            "description": "The workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Workspace"
                },
                "example": {
                  "id": "tq7x2m9k4ab",
                  "name": "Northwind Logistics",
                  "tier": "shared",
                  "external_ref": null,
                  "quotas": {
                    "max_users": 50,
                    "max_devices": 100,
                    "max_connections": 25,
                    "max_connectors": 5,
                    "max_private_networks": 3
                  },
                  "usage": {
                    "users": 18,
                    "devices": 23,
                    "connections": 7,
                    "connectors": 2,
                    "private_networks": 1
                  },
                  "status": {
                    "phase": "ready",
                    "observed_at": "2026-10-01T08:00:00.000Z",
                    "message": null
                  },
                  "version": 42,
                  "created_at": "2026-09-14T10:12:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      },
      "patch": {
        "tags": [
          "Workspace"
        ],
        "operationId": "renameWorkspace",
        "summary": "Rename the workspace",
        "description": "Changes the workspace display name. Plan limits (`quotas`) cannot be changed with an API token. Send `If-Match: <version>` to fail instead of overwriting a change made in the meantime.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "New display name, 1-80 characters, without `< > \" ' ` & \\`."
                  }
                },
                "required": [
                  "name"
                ]
              },
              "example": {
                "name": "Northwind Logistics IL"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Workspace"
                },
                "example": {
                  "id": "tq7x2m9k4ab",
                  "name": "Northwind Logistics IL",
                  "tier": "shared",
                  "external_ref": null,
                  "quotas": {
                    "max_users": 50,
                    "max_devices": 100,
                    "max_connections": 25,
                    "max_connectors": 5,
                    "max_private_networks": 3
                  },
                  "usage": {
                    "users": 18,
                    "devices": 23,
                    "connections": 7,
                    "connectors": 2,
                    "private_networks": 1
                  },
                  "status": {
                    "phase": "ready",
                    "observed_at": "2026-10-01T08:00:00.000Z",
                    "message": null
                  },
                  "version": 43,
                  "created_at": "2026-09-14T10:12:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "`invalid-name`: The name is empty, longer than 80 characters or contains a forbidden character.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-name": {
                    "summary": "The name is empty, longer than 80 characters or contains a forbidden character.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-name",
                      "code": "invalid-name",
                      "title": "invalid name",
                      "status": 400,
                      "detail": "The name is empty, longer than 80 characters or contains a forbidden character."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`platform-scope-required`: The body tried to change `quotas` (plan limits are changed by Cloudraw).\n\n`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "platform-scope-required": {
                    "summary": "The body tried to change `quotas` (plan limits are changed by Cloudraw).",
                    "value": {
                      "type": "https://cloudraw.com/problems/platform-scope-required",
                      "code": "platform-scope-required",
                      "title": "platform scope required",
                      "status": 403,
                      "detail": "The body tried to change quotas (plan limits are changed by Cloudraw)."
                    }
                  },
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`version-conflict`: `If-Match` does not match the current `version`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "version-conflict": {
                    "summary": "`If-Match` does not match the current `version`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/version-conflict",
                      "code": "version-conflict",
                      "title": "version conflict",
                      "status": 409,
                      "detail": "If-Match does not match the current version."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/access-history": {
      "get": {
        "tags": [
          "Sessions"
        ],
        "operationId": "listAccessHistory",
        "summary": "List access history",
        "description": "Who used which app or private network, from which device, when and for how long — open sessions (`live: true`) and closed ones, newest first, with per-app totals. Where the connector reports it, entries also carry the exact destination address inside your network and byte counts. History is kept 30 days; sessions shorter than about 30 seconds may be missing, and Cloudraw Connect's automatic reachability checks are left out.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "days",
            "in": "query",
            "required": false,
            "description": "Look-back window in days, 1-30 (out-of-range values are clamped). Default 7.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 30,
              "default": 7
            },
            "example": 7
          },
          {
            "name": "device_id",
            "in": "query",
            "required": false,
            "description": "Only this device.",
            "schema": {
              "type": "string"
            },
            "example": "dvc_5mxq2b7r8k"
          },
          {
            "name": "person_id",
            "in": "query",
            "required": false,
            "description": "Only this person.",
            "schema": {
              "type": "string"
            },
            "example": "pz81kd03mna"
          },
          {
            "name": "connection_id",
            "in": "query",
            "required": false,
            "description": "Only this app (connection).",
            "schema": {
              "type": "string"
            },
            "example": "cx9m2v7d1pa"
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "description": "Only this kind of session.",
            "schema": {
              "type": "string",
              "enum": [
                "device",
                "browser",
                "other"
              ]
            }
          },
          {
            "name": "include_probes",
            "in": "query",
            "required": false,
            "description": "true = also list the automatic Cloudraw Connect reachability checks, each labelled `probe: true` (for exports); they never count in `by_app`.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum entries, 1-1000 (clamped). Default 200. There is no next page: narrow the window or filters instead.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1000,
              "default": 200
            },
            "example": 200
          }
        ],
        "responses": {
          "200": {
            "description": "Access history for the window (not paginated).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccessHistory"
                },
                "example": {
                  "days": 7,
                  "items": [
                    {
                      "id": "ovl_7f3k9x2m0qd8s1a",
                      "live": false,
                      "kind": "device",
                      "device_id": "dvc_5mxq2b7r8k",
                      "device_name": "DANA-LAPTOP",
                      "person_id": "pz81kd03mna",
                      "user": "Dana Levi",
                      "app": "Office LAN",
                      "connection_id": null,
                      "private_network_id": "pn_6b2x9q0wea",
                      "target": {
                        "type": "private_network",
                        "cidrs": [
                          "10.20.0.0/24"
                        ],
                        "translated_cidr": null
                      },
                      "via": "cloudraw connect",
                      "ip": null,
                      "edge": "edge-1",
                      "path": "edge-1 → edge-3",
                      "started_at": "2026-10-13T07:02:10.000Z",
                      "ended_at": "2026-10-13T07:48:40.000Z",
                      "duration_s": 2790,
                      "dst": {
                        "proto": "tcp",
                        "ip": "10.20.0.15",
                        "port": 445
                      },
                      "bytes_in": 18233411,
                      "bytes_out": 902114,
                      "end_reason": "closed",
                      "reported_by": "cn0r4w8t2kq"
                    }
                  ],
                  "by_app": [
                    {
                      "app": "Office LAN",
                      "sessions": 1,
                      "total_s": 2790
                    }
                  ],
                  "probes_excluded": 4,
                  "retention_days": 30,
                  "note": "Sessions shorter than about 30 seconds may be missing. The exact address inside a private network is coming with the connector update."
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/alerts:triage": {
      "post": {
        "tags": [
          "Alerts"
        ],
        "operationId": "triageAlerts",
        "summary": "Triage alerts in bulk",
        "description": "Applies one triage action to up to 200 alerts and/or security events. All ids are checked first: if any is unknown, nothing changes (`invalid-items`). Alerts whose current status does not allow the action — or a dismiss without a valid `reason` / required `note` — are skipped and reported in `results`; the others change. Each change is audited and streamed to your SIEM.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "items": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "kind": {
                          "type": "string",
                          "enum": [
                            "notification",
                            "security_event"
                          ]
                        },
                        "id": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "kind",
                        "id"
                      ]
                    },
                    "description": "1-200 alerts (items beyond 200 are ignored)."
                  },
                  "action": {
                    "type": "string",
                    "enum": [
                      "acknowledge",
                      "resolve",
                      "dismiss",
                      "reopen"
                    ]
                  },
                  "reason": {
                    "type": "string",
                    "enum": [
                      "false_positive",
                      "expected_activity",
                      "benign",
                      "duplicate",
                      "accepted_risk"
                    ],
                    "description": "Required for `dismiss`."
                  },
                  "note": {
                    "type": "string",
                    "description": "Up to 1000 characters. Required for `dismiss` of `bad` alerts."
                  },
                  "assignee": {
                    "type": "string",
                    "description": "For `acknowledge`: who owns them. Default: the caller."
                  }
                },
                "required": [
                  "items",
                  "action"
                ]
              },
              "example": {
                "items": [
                  {
                    "kind": "security_event",
                    "id": "sev_9x2k0m8s1d"
                  },
                  {
                    "kind": "notification",
                    "id": "ntf_4k2x9m0s8d"
                  }
                ],
                "action": "dismiss",
                "reason": "duplicate",
                "note": "Same incident as SOC ticket 4411."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "What happened to each alert.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertBulkTriageResult"
                },
                "example": {
                  "action": "dismiss",
                  "done": 1,
                  "skipped": 1,
                  "results": [
                    {
                      "kind": "security_event",
                      "id": "sev_9x2k0m8s1d",
                      "ok": true,
                      "error": null,
                      "status": "dismissed"
                    },
                    {
                      "kind": "notification",
                      "id": "ntf_4k2x9m0s8d",
                      "ok": false,
                      "error": "this alert is resolved; dismiss works from new / acknowledged",
                      "status": "resolved"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "`items-required`: `items` is missing or empty.\n\n`invalid-action`: `action` is not acknowledge, resolve, dismiss or reopen.\n\n`invalid-items`: One or more items were not found (see `errors[]` with the item index); nothing was changed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "items-required": {
                    "summary": "`items` is missing or empty.",
                    "value": {
                      "type": "https://cloudraw.com/problems/items-required",
                      "code": "items-required",
                      "title": "items required",
                      "status": 400,
                      "detail": "items is missing or empty."
                    }
                  },
                  "invalid-action": {
                    "summary": "`action` is not acknowledge, resolve, dismiss or reopen.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-action",
                      "code": "invalid-action",
                      "title": "invalid action",
                      "status": 400,
                      "detail": "action is not acknowledge, resolve, dismiss or reopen."
                    }
                  },
                  "invalid-items": {
                    "summary": "One or more items were not found (see `errors[]` with the item index); nothing was changed.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-items",
                      "code": "invalid-items",
                      "title": "invalid items",
                      "status": 400,
                      "detail": "One or more items were not found (see errors[] with the item index); nothing was changed."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/audit": {
      "get": {
        "tags": [
          "Audit log"
        ],
        "operationId": "listAuditEntries",
        "summary": "List audit log entries",
        "description": "The audit log of your workspace, newest first: every change made in the console, through the API, by an integrator, by Cloudraw support or automatically. Filters combine (AND). Pages stay stable while new entries are written, so you can poll from the top and stop when you reach an entry you already have (compare `tseq`). Actor names are shown in readable form (for example \"Cloudraw support (<name>) for case SC-…\"); use `GET …/audit/export` for the stored entries as written.\n\nTo have entries pushed to your SIEM instead of polling, see the Log streaming endpoints (`…/siem`) under the **Log streaming** tag.\n\n**Token:** read-only or full access · **Created by:** owner or security admin\n\n**Pagination:** cursor based — see [Pagination](/docs/api/pagination).\n\n`limit`: 1-1000, default 200.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "action",
            "in": "query",
            "required": false,
            "description": "Only actions starting with this text (prefix match): `device.` = every device action, `person.invite` = invites.",
            "schema": {
              "type": "string"
            },
            "example": "device."
          },
          {
            "name": "actor",
            "in": "query",
            "required": false,
            "description": "Only entries by this actor, exact match on the stored actor (an admin e-mail, or `token:<token name>`).",
            "schema": {
              "type": "string"
            },
            "example": "dana.levi@example.com"
          },
          {
            "name": "target",
            "in": "query",
            "required": false,
            "description": "Only entries that name this id (person, device, app, connector, private network, rule, grant, session, token, …) — the \"Activity\" of one object. Up to 80 characters.",
            "schema": {
              "type": "string"
            },
            "example": "dvc_5mxq2b7r8k"
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "Only entries at or after this time (ISO 8601, UTC).",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-10-01T00:00:00Z"
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "description": "Only entries at or before this time (ISO 8601, UTC).",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-10-13T23:59:59Z"
          },
          {
            "name": "actor_kind",
            "in": "query",
            "required": false,
            "description": "Only actions by integrator staff (`partner`) or by Cloudraw support (`cloudraw_support`).",
            "schema": {
              "type": "string",
              "enum": [
                "partner",
                "cloudraw_support"
              ]
            }
          },
          {
            "name": "partner_id",
            "in": "query",
            "required": false,
            "description": "Everything about one integrator: its staff's actions and its access link events.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{2,40}$"
            }
          },
          {
            "name": "support_grant",
            "in": "query",
            "required": false,
            "description": "Every entry of one Cloudraw support access grant (request, decision, actions under it, end).",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{2,64}$"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size.",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 50
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pass back `next_cursor` from the previous page, unchanged. Omit for the first page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of entries.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuditPage"
                },
                "example": {
                  "items": [
                    {
                      "at": "2026-10-13T09:24:11.000Z",
                      "tseq": 1842,
                      "action": "device.quarantine",
                      "tenant": "tq7x2m9k4ab",
                      "actor": "dana.levi@example.com",
                      "actor_role": "security_admin",
                      "via": "panel",
                      "ip": "203.0.113.24",
                      "req_id": "req_8k2x0m9s1d4f",
                      "device": "dvc_5mxq2b7r8k",
                      "reason": "Suspicious sign-in",
                      "sessions_cut": 1,
                      "sessions_failed": 0,
                      "alg": "hmac",
                      "hash": "6f1c2a9e0b4d7f38a5c1e2d9b0f4a7c3e8d1b6f2a9c0e7d4b3f8a1c6e2d9b0f4"
                    }
                  ],
                  "next_cursor": "YTM6MTg0Mg",
                  "next_page": null
                }
              }
            }
          },
          "400": {
            "description": "`invalid-limit`: `limit` is not an integer from 1 to 1000.\n\n`invalid-cursor`: `cursor` is not a `next_cursor` from this API (pass it back unchanged).\n\n`invalid-partner-id`: `partner_id` is not an integrator id.\n\n`invalid-actor-kind`: `actor_kind` is not `partner` or `cloudraw_support`.\n\n`invalid-support-grant`: `support_grant` is not a support grant id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-limit": {
                    "summary": "`limit` is not an integer from 1 to 1000.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-limit",
                      "code": "invalid-limit",
                      "title": "invalid limit",
                      "status": 400,
                      "detail": "limit is not an integer from 1 to 1000."
                    }
                  },
                  "invalid-cursor": {
                    "summary": "`cursor` is not a `next_cursor` from this API (pass it back unchanged).",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-cursor",
                      "code": "invalid-cursor",
                      "title": "invalid cursor",
                      "status": 400,
                      "detail": "cursor is not a next_cursor from this API (pass it back unchanged)."
                    }
                  },
                  "invalid-partner-id": {
                    "summary": "`partner_id` is not an integrator id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-partner-id",
                      "code": "invalid-partner-id",
                      "title": "invalid partner id",
                      "status": 400,
                      "detail": "partner_id is not an integrator id."
                    }
                  },
                  "invalid-actor-kind": {
                    "summary": "`actor_kind` is not `partner` or `cloudraw_support`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-actor-kind",
                      "code": "invalid-actor-kind",
                      "title": "invalid actor kind",
                      "status": 400,
                      "detail": "actor_kind is not partner or cloudraw_support."
                    }
                  },
                  "invalid-support-grant": {
                    "summary": "`support_grant` is not a support grant id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-support-grant",
                      "code": "invalid-support-grant",
                      "title": "invalid support grant",
                      "status": 400,
                      "detail": "support_grant is not a support grant id."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`audit-unavailable`: The audit log cannot be read right now. Retry shortly.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "audit-unavailable": {
                    "summary": "The audit log cannot be read right now. Retry shortly.",
                    "value": {
                      "type": "https://cloudraw.com/problems/audit-unavailable",
                      "code": "audit-unavailable",
                      "title": "audit unavailable",
                      "status": 503,
                      "detail": "The audit log cannot be read right now. Retry shortly."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/audit/export": {
      "get": {
        "tags": [
          "Audit log"
        ],
        "operationId": "exportAuditLog",
        "summary": "Export the audit log",
        "description": "Downloads audit entries as newline-delimited JSON (one entry per line, newest first), as a file attachment `cloudraw-audit-<workspace>.jsonl`. Takes the same filters as `GET …/audit`, up to 10,000 entries per call; use `since` / `until` (or `cursor`) to export larger ranges in parts. Entries are exactly as stored (actor fields are not rewritten for display), so their hashes can be checked. Every export is itself written to the audit log (`audit.export`), and so is a refused one (`export.rate_limited`).\n\n**Token:** read-only or full access · **Created by:** owner or security admin\n\n**Pagination:** cursor based — see [Pagination](/docs/api/pagination).\n\n**Rate limit:** 10 exports per hour per admin (or API token) per workspace, shared with the integrator review export. Over it: `429 rate-limited` with `Retry-After` and `retry_after_s`.\n\n`limit`: 1-10000, default 10000. The file has no `next_cursor`: to continue, pass `until` = the `at` of the last line, or `cursor`. For continuous delivery use Log streaming (`…/siem`, **Log streaming** tag).",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "action",
            "in": "query",
            "required": false,
            "description": "Only actions starting with this text (prefix match): `device.` = every device action, `person.invite` = invites.",
            "schema": {
              "type": "string"
            },
            "example": "device."
          },
          {
            "name": "actor",
            "in": "query",
            "required": false,
            "description": "Only entries by this actor, exact match on the stored actor (an admin e-mail, or `token:<token name>`).",
            "schema": {
              "type": "string"
            },
            "example": "dana.levi@example.com"
          },
          {
            "name": "target",
            "in": "query",
            "required": false,
            "description": "Only entries that name this id (person, device, app, connector, private network, rule, grant, session, token, …) — the \"Activity\" of one object. Up to 80 characters.",
            "schema": {
              "type": "string"
            },
            "example": "dvc_5mxq2b7r8k"
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "Only entries at or after this time (ISO 8601, UTC).",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-10-01T00:00:00Z"
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "description": "Only entries at or before this time (ISO 8601, UTC).",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-10-13T23:59:59Z"
          },
          {
            "name": "actor_kind",
            "in": "query",
            "required": false,
            "description": "Only actions by integrator staff (`partner`) or by Cloudraw support (`cloudraw_support`).",
            "schema": {
              "type": "string",
              "enum": [
                "partner",
                "cloudraw_support"
              ]
            }
          },
          {
            "name": "partner_id",
            "in": "query",
            "required": false,
            "description": "Everything about one integrator: its staff's actions and its access link events.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{2,40}$"
            }
          },
          {
            "name": "support_grant",
            "in": "query",
            "required": false,
            "description": "Every entry of one Cloudraw support access grant (request, decision, actions under it, end).",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{2,64}$"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size.",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 50
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pass back `next_cursor` from the previous page, unchanged. Omit for the first page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "NDJSON file: one `AuditEntry` per line. Empty file when nothing matches.",
            "headers": {
              "Content-Disposition": {
                "description": "`attachment; filename=\"cloudraw-audit-<workspace id>.jsonl\"`",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/x-ndjson": {
                "schema": {
                  "type": "string",
                  "description": "One JSON-encoded AuditEntry per line."
                },
                "example": "{\"at\":\"2026-10-13T09:24:11.000Z\",\"tseq\":1842,\"action\":\"device.quarantine\",\"tenant\":\"tq7x2m9k4ab\",\"actor\":\"dana.levi@example.com\",\"actor_role\":\"security_admin\",\"via\":\"panel\",\"ip\":\"203.0.113.24\",\"req_id\":\"req_8k2x0m9s1d4f\",\"device\":\"dvc_5mxq2b7r8k\",\"reason\":\"Suspicious sign-in\",\"sessions_cut\":1,\"sessions_failed\":0,\"alg\":\"hmac\",\"hash\":\"6f1c2a9e0b4d7f38a5c1e2d9b0f4a7c3e8d1b6f2a9c0e7d4b3f8a1c6e2d9b0f4\"}\n{\"at\":\"2026-10-13T09:20:02.000Z\",\"tseq\":1841,\"action\":\"person.invite\",\"tenant\":\"tq7x2m9k4ab\",\"actor\":\"token:hr-sync\",\"actor_role\":\"owner\",\"via\":\"api\",\"ip\":\"198.51.100.7\",\"req_id\":\"req_2m0x9k8s1d3a\",\"person\":\"p4hd8s0qk2l\",\"alg\":\"hmac\",\"hash\":\"a0c4e8f2b6d1937c5e0a8f4b2d6c1e9a7f3b5d0c8e2a6f4b1d9c7e3a5f0b8d2c\"}\n"
              }
            }
          },
          "400": {
            "description": "`invalid-limit`: `limit` is not an integer from 1 to 10000.\n\n`invalid-cursor`: `cursor` is not a `next_cursor` from this API.\n\n`invalid-partner-id`: `partner_id` is not an integrator id.\n\n`invalid-actor-kind`: `actor_kind` is not `partner` or `cloudraw_support`.\n\n`invalid-support-grant`: `support_grant` is not a support grant id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-limit": {
                    "summary": "`limit` is not an integer from 1 to 10000.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-limit",
                      "code": "invalid-limit",
                      "title": "invalid limit",
                      "status": 400,
                      "detail": "limit is not an integer from 1 to 10000."
                    }
                  },
                  "invalid-cursor": {
                    "summary": "`cursor` is not a `next_cursor` from this API.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-cursor",
                      "code": "invalid-cursor",
                      "title": "invalid cursor",
                      "status": 400,
                      "detail": "cursor is not a next_cursor from this API."
                    }
                  },
                  "invalid-partner-id": {
                    "summary": "`partner_id` is not an integrator id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-partner-id",
                      "code": "invalid-partner-id",
                      "title": "invalid partner id",
                      "status": 400,
                      "detail": "partner_id is not an integrator id."
                    }
                  },
                  "invalid-actor-kind": {
                    "summary": "`actor_kind` is not `partner` or `cloudraw_support`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-actor-kind",
                      "code": "invalid-actor-kind",
                      "title": "invalid actor kind",
                      "status": 400,
                      "detail": "actor_kind is not partner or cloudraw_support."
                    }
                  },
                  "invalid-support-grant": {
                    "summary": "`support_grant` is not a support grant id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-support-grant",
                      "code": "invalid-support-grant",
                      "title": "invalid support grant",
                      "status": 400,
                      "detail": "support_grant is not a support grant id."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate-limited`: More than 10 exports in the last hour by this admin or token. Wait `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "rate-limited": {
                    "summary": "More than 10 exports in the last hour by this admin or token. Wait `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/rate-limited",
                      "code": "rate-limited",
                      "title": "rate limited",
                      "status": 429,
                      "detail": "More than 10 exports in the last hour by this admin or token. Wait Retry-After seconds."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`audit-unavailable`: The audit log cannot be read right now. Retry shortly.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "audit-unavailable": {
                    "summary": "The audit log cannot be read right now. Retry shortly.",
                    "value": {
                      "type": "https://cloudraw.com/problems/audit-unavailable",
                      "code": "audit-unavailable",
                      "title": "audit unavailable",
                      "status": 503,
                      "detail": "The audit log cannot be read right now. Retry shortly."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        },
        "x-cloudraw-rate-limit": "10 exports per hour per admin (or API token) per workspace, shared with the integrator review export. Over it: `429 rate-limited` with `Retry-After` and `retry_after_s`."
      }
    },
    "/v0/tenants/{tenant_id}/audit/verify": {
      "get": {
        "tags": [
          "Audit log"
        ],
        "operationId": "verifyAuditLog",
        "summary": "Verify the audit log",
        "description": "Re-checks the tamper-evident hash chain the audit log is written in and tells you whether it is intact. Each entry's `hash` covers its content and the previous entry, so any edit, reordering or deletion breaks the chain. You get your workspace's entry count and highest `tseq`: if your stored copy has every number from 1 to `tenant_seq_head`, you have the complete log. A break is never repaired silently — Cloudraw operations is alerted and the break stays on record.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "responses": {
          "200": {
            "description": "The verdict.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuditVerification"
                },
                "example": {
                  "ok": true,
                  "tenant_entries": 1842,
                  "tenant_seq_head": 1842,
                  "verified_at": "2026-10-13T09:24:11.000Z",
                  "detail": "Every entry in the platform audit chain verified; your entries are part of it."
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`audit-unavailable`: The audit log cannot be read right now. Retry shortly.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "audit-unavailable": {
                    "summary": "The audit log cannot be read right now. Retry shortly.",
                    "value": {
                      "type": "https://cloudraw.com/problems/audit-unavailable",
                      "code": "audit-unavailable",
                      "title": "audit unavailable",
                      "status": 503,
                      "detail": "The audit log cannot be read right now. Retry shortly."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/connections": {
      "get": {
        "tags": [
          "Apps"
        ],
        "operationId": "listConnections",
        "summary": "List applications",
        "description": "Returns every application (connection) published in the workspace, with its target, hosting connectors and session controls. The list is not paginated (it is bounded by the plan's application limit).\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "responses": {
          "200": {
            "description": "All applications.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnectionList"
                },
                "example": {
                  "items": [
                    {
                      "id": "cx9m2v7d1pa",
                      "name": "finance-terminal",
                      "display_name": "Finance terminal",
                      "type": "rdp",
                      "host": "10.20.0.15",
                      "port": 3389,
                      "connector_id": "cn0r4w8t2kq",
                      "connector_ids": [
                        "cn0r4w8t2kq"
                      ],
                      "rdp_security": "any",
                      "rdp_domain": null,
                      "access_groups": [],
                      "clientless": true,
                      "intercept": "finance-terminal.q7x2m.cloudraw",
                      "status": {
                        "phase": "ready",
                        "observed_at": "2026-10-13T09:24:11.000Z",
                        "message": null
                      },
                      "version": 1,
                      "created_by_integrator": null,
                      "delivery": {
                        "client": true,
                        "portal": true,
                        "rbi": false,
                        "onetime_rdp": false,
                        "native": false
                      },
                      "recording": {
                        "on": false,
                        "required": false,
                        "mode": null,
                        "notice": {
                          "on": false,
                          "mandatory": true,
                          "text": "This session is recorded. What you see and do on screen is saved for security and compliance, and authorized people in your organization can watch it later.",
                          "custom": false,
                          "default_text": "This session is recorded. What you see and do on screen is saved for security and compliance, and authorized people in your organization can watch it later."
                        }
                      },
                      "redirection": {
                        "clipboard_in": true,
                        "clipboard_out": false,
                        "drives": false,
                        "printers": false,
                        "audio_out": true,
                        "mic": false,
                        "camera": false,
                        "usb": false
                      },
                      "reauth": {
                        "every_minutes": null
                      },
                      "posture": [],
                      "appfw": {
                        "mode": "off",
                        "allow": []
                      },
                      "redirection_rules": [],
                      "allowed_apps": null,
                      "remote_app": null,
                      "gateway_only": {
                        "on": false,
                        "reason": null
                      },
                      "guides": {
                        "app": {
                          "id": "app-remote-app",
                          "section": null,
                          "title": "Publish a remote desktop",
                          "url": "https://cdapi.cloudraw.com/guides/app-remote-app",
                          "pdf_url": null
                        },
                        "allowed_apps": {
                          "id": "app-allowed-apps",
                          "section": null,
                          "title": "Allowed applications",
                          "url": "https://cdapi.cloudraw.com/guides/app-allowed-apps",
                          "pdf_url": null
                        },
                        "alerts": {
                          "id": "app-allowed-apps",
                          "section": null,
                          "title": "Allowed applications",
                          "url": "https://cdapi.cloudraw.com/guides/app-allowed-apps",
                          "pdf_url": null
                        }
                      },
                      "icon": null,
                      "browser": {
                        "supported": true,
                        "ready": true,
                        "error": null,
                        "opens": "desktop"
                      },
                      "controls_enforcement": {
                        "delivery": "stored",
                        "recording": "partial:browser_sessions_only",
                        "redirection": "partial:browser_sessions_only",
                        "reauth": "stored",
                        "posture": "stored",
                        "appfw": "stored",
                        "allowed_apps": "partial:client_min_version"
                      }
                    },
                    {
                      "id": "cx4k8d2m0sq",
                      "name": "file-server",
                      "display_name": "File server",
                      "type": "smb",
                      "host": "fs01.corp.example.local",
                      "port": 445,
                      "connector_id": "cn0r4w8t2kq",
                      "connector_ids": [
                        "cn0r4w8t2kq"
                      ],
                      "access_groups": [],
                      "clientless": null,
                      "intercept": "fs01.corp.example.local",
                      "status": {
                        "phase": "ready",
                        "observed_at": "2026-10-13T09:24:11.000Z",
                        "message": null
                      },
                      "version": 1,
                      "created_by_integrator": null,
                      "delivery": {
                        "client": true,
                        "portal": false,
                        "rbi": false,
                        "onetime_rdp": false,
                        "native": false
                      },
                      "recording": {
                        "on": false,
                        "required": false,
                        "mode": null,
                        "notice": {
                          "on": false,
                          "mandatory": true,
                          "text": "This session is recorded. What you see and do on screen is saved for security and compliance, and authorized people in your organization can watch it later.",
                          "custom": false,
                          "default_text": "This session is recorded. What you see and do on screen is saved for security and compliance, and authorized people in your organization can watch it later."
                        }
                      },
                      "redirection": {
                        "clipboard_in": true,
                        "clipboard_out": false,
                        "drives": false,
                        "printers": false,
                        "audio_out": true,
                        "mic": false,
                        "camera": false,
                        "usb": false
                      },
                      "reauth": {
                        "every_minutes": null
                      },
                      "posture": [],
                      "appfw": {
                        "mode": "off",
                        "allow": []
                      },
                      "redirection_rules": [],
                      "allowed_apps": null,
                      "gateway_only": {
                        "on": false,
                        "reason": null
                      },
                      "guides": {
                        "app": {
                          "id": "app-smb",
                          "section": null,
                          "title": "Publish a file server",
                          "url": "https://cdapi.cloudraw.com/guides/app-smb",
                          "pdf_url": null
                        },
                        "allowed_apps": {
                          "id": "app-allowed-apps",
                          "section": null,
                          "title": "Allowed applications",
                          "url": "https://cdapi.cloudraw.com/guides/app-allowed-apps",
                          "pdf_url": null
                        },
                        "alerts": {
                          "id": "app-allowed-apps",
                          "section": null,
                          "title": "Allowed applications",
                          "url": "https://cdapi.cloudraw.com/guides/app-allowed-apps",
                          "pdf_url": null
                        }
                      },
                      "icon": null,
                      "browser": null,
                      "controls_enforcement": {
                        "delivery": "stored",
                        "recording": "partial:browser_sessions_only",
                        "redirection": "partial:browser_sessions_only",
                        "reauth": "stored",
                        "posture": "stored",
                        "appfw": "stored",
                        "allowed_apps": "partial:client_min_version"
                      },
                      "shares": [
                        {
                          "share": "Finance",
                          "path": null,
                          "drive_letter": "F",
                          "access": "rw",
                          "label": "Finance",
                          "unc": "\\\\fs01.corp.example.local\\Finance"
                        }
                      ],
                      "protection_profile_id": null,
                      "smb_mode": "direct",
                      "share_policy_enforced": false,
                      "service_account": {
                        "configured": false
                      },
                      "protection": null,
                      "share_check": null,
                      "files_security": null
                    }
                  ],
                  "next_page": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      },
      "post": {
        "tags": [
          "Apps"
        ],
        "operationId": "createConnection",
        "summary": "Create an application",
        "description": "Publishes an application through one or more of your connectors. Zero trust: a new application is reachable by **no one** until an access rule grants it. Recording, redirection and re-authentication start from the workspace session policy. Audited.\n\nWhat each `type` needs:\n- **`rdp`, `ssh`, `vnc`, `http`, `https`, `tcp`, `db`** (and any other type label): `name`, `host`, `port`, `connector_id`. Devices reach it at `intercept` (`<name>.<id>.cloudraw`). Only `rdp`, `ssh` and `vnc` can also open in the browser (`clientless: true`).\n- **RemoteApp**: `type: \"rdp\"` plus `remote_app: {program}` — the session opens one program instead of the desktop. A plain program path needs a one-time setup command on the server (see `remote_app.setup` in the answer).\n- **`smb`** (Windows file server): `name`, `host` (server name), `shares` (1-20), `connector_id`; the port is always 445. One application per file server; devices keep using the real server name. `smb_mode: \"gateway\"` makes it a protected file server reached only through the Cloudraw file gateway.\n- **`egress`** (public website / SaaS that allow-lists your connector's public IP): `name`, `hostnames` (1-20), optional `ports` (default 443 and 80), `connector_id`; no `host`/`port`. The host names must resolve to public addresses.\n\n**Token:** full access · **Created by:** owner\n\n**Idempotency:** send `Idempotency-Key` to retry safely — the same key and body within 24 h returns the first answer.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConnectionCreate"
              },
              "example": {
                "name": "Finance terminal",
                "type": "rdp",
                "host": "10.20.0.15",
                "port": 3389,
                "connector_id": "cn0r4w8t2kq",
                "clientless": true
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new application.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Connection"
                },
                "example": {
                  "id": "cx9m2v7d1pa",
                  "name": "finance-terminal",
                  "display_name": "Finance terminal",
                  "type": "rdp",
                  "host": "10.20.0.15",
                  "port": 3389,
                  "connector_id": "cn0r4w8t2kq",
                  "connector_ids": [
                    "cn0r4w8t2kq"
                  ],
                  "rdp_security": "any",
                  "rdp_domain": null,
                  "access_groups": [],
                  "clientless": true,
                  "intercept": "finance-terminal.q7x2m.cloudraw",
                  "status": {
                    "phase": "ready",
                    "observed_at": "2026-10-13T09:24:11.000Z",
                    "message": null
                  },
                  "version": 1,
                  "created_by_integrator": null,
                  "delivery": {
                    "client": true,
                    "portal": true,
                    "rbi": false,
                    "onetime_rdp": false,
                    "native": false
                  },
                  "recording": {
                    "on": false,
                    "required": false,
                    "mode": null,
                    "notice": {
                      "on": false,
                      "mandatory": true,
                      "text": "This session is recorded. What you see and do on screen is saved for security and compliance, and authorized people in your organization can watch it later.",
                      "custom": false,
                      "default_text": "This session is recorded. What you see and do on screen is saved for security and compliance, and authorized people in your organization can watch it later."
                    }
                  },
                  "redirection": {
                    "clipboard_in": true,
                    "clipboard_out": false,
                    "drives": false,
                    "printers": false,
                    "audio_out": true,
                    "mic": false,
                    "camera": false,
                    "usb": false
                  },
                  "reauth": {
                    "every_minutes": null
                  },
                  "posture": [],
                  "appfw": {
                    "mode": "off",
                    "allow": []
                  },
                  "redirection_rules": [],
                  "allowed_apps": null,
                  "remote_app": null,
                  "gateway_only": {
                    "on": false,
                    "reason": null
                  },
                  "guides": {
                    "app": {
                      "id": "app-remote-app",
                      "section": null,
                      "title": "Publish a remote desktop",
                      "url": "https://cdapi.cloudraw.com/guides/app-remote-app",
                      "pdf_url": null
                    },
                    "allowed_apps": {
                      "id": "app-allowed-apps",
                      "section": null,
                      "title": "Allowed applications",
                      "url": "https://cdapi.cloudraw.com/guides/app-allowed-apps",
                      "pdf_url": null
                    },
                    "alerts": {
                      "id": "app-allowed-apps",
                      "section": null,
                      "title": "Allowed applications",
                      "url": "https://cdapi.cloudraw.com/guides/app-allowed-apps",
                      "pdf_url": null
                    }
                  },
                  "icon": null,
                  "browser": {
                    "supported": true,
                    "ready": true,
                    "error": null,
                    "opens": "desktop"
                  },
                  "controls_enforcement": {
                    "delivery": "stored",
                    "recording": "partial:browser_sessions_only",
                    "redirection": "partial:browser_sessions_only",
                    "reauth": "stored",
                    "posture": "stored",
                    "appfw": "stored",
                    "allowed_apps": "partial:client_min_version"
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid-name`: `name` is not 1-80 characters, without `< > \" ' ` & \\` or quote marks.\n\n`name-type-host-port-connector-id-required`: A field required for this type is missing (`name`, `type`, `host`, `port`, `connector_id`).\n\n`name-host-connector-id-required`: `smb`: `name`, `host` or `connector_id` is missing.\n\n`name-connector-id-required`: `egress`: `name` or `connector_id` is missing.\n\n`invalid-egress`: `egress`: `hostnames` is empty, has more than 20 entries, an invalid or too broad wildcard, a Cloudraw name, a name that does not resolve or resolves to a private address; or `ports` is not 1-10 ports in 1-65535.\n\n`invalid-share`: `smb`: `host` is not a server name / IPv4 address, or `shares` is invalid (count, name, sub-folder, drive letter D-Z, duplicate, `access`).\n\n`invalid-smb-mode`: `smb_mode` is not `direct` or `gateway`.\n\n`unknown-protection-profile-id`: `protection_profile_id` does not exist.\n\n`unknown-connector-id`: `connector_id` or one of `connector_ids` does not exist or is being removed.\n\n`too-many-connectors`: More than 5 hosting connectors.\n\n`invalid-remote-app`: `remote_app` on a non-`rdp` type, or `remote_app.program` is empty, longer than 260 characters or has a line break / `\"`.\n\n`invalid-clientless`: `clientless` is not a boolean.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-name": {
                    "summary": "`name` is not 1-80 characters, without `< > \" ' ` & \\` or quote marks.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-name",
                      "code": "invalid-name",
                      "title": "invalid name",
                      "status": 400,
                      "detail": "name is not 1-80 characters, without < > \" '  & \\ or quote marks."
                    }
                  },
                  "name-type-host-port-connector-id-required": {
                    "summary": "A field required for this type is missing (`name`, `type`, `host`, `port`, `connector_id`).",
                    "value": {
                      "type": "https://cloudraw.com/problems/name-type-host-port-connector-id-required",
                      "code": "name-type-host-port-connector-id-required",
                      "title": "name type host port connector id required",
                      "status": 400,
                      "detail": "A field required for this type is missing (name, type, host, port, connector_id)."
                    }
                  },
                  "name-host-connector-id-required": {
                    "summary": "`smb`: `name`, `host` or `connector_id` is missing.",
                    "value": {
                      "type": "https://cloudraw.com/problems/name-host-connector-id-required",
                      "code": "name-host-connector-id-required",
                      "title": "name host connector id required",
                      "status": 400,
                      "detail": "smb: name, host or connector_id is missing."
                    }
                  },
                  "name-connector-id-required": {
                    "summary": "`egress`: `name` or `connector_id` is missing.",
                    "value": {
                      "type": "https://cloudraw.com/problems/name-connector-id-required",
                      "code": "name-connector-id-required",
                      "title": "name connector id required",
                      "status": 400,
                      "detail": "egress: name or connector_id is missing."
                    }
                  },
                  "invalid-egress": {
                    "summary": "`egress`: `hostnames` is empty, has more than 20 entries, an invalid or too broad wildcard, a Cloudraw name, a name that does not resolve or resolves to a private address; or `ports` is not 1-10 ports in 1-65535.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-egress",
                      "code": "invalid-egress",
                      "title": "invalid egress",
                      "status": 400,
                      "detail": "egress: hostnames is empty, has more than 20 entries, an invalid or too broad wildcard, a Cloudraw name, a name that does not resolve or resolves to a private address; or ports is not 1-10 ports in 1-65535."
                    }
                  },
                  "invalid-share": {
                    "summary": "`smb`: `host` is not a server name / IPv4 address, or `shares` is invalid (count, name, sub-folder, drive letter D-Z, duplicate, `access`).",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-share",
                      "code": "invalid-share",
                      "title": "invalid share",
                      "status": 400,
                      "detail": "smb: host is not a server name / IPv4 address, or shares is invalid (count, name, sub-folder, drive letter D-Z, duplicate, access)."
                    }
                  },
                  "invalid-smb-mode": {
                    "summary": "`smb_mode` is not `direct` or `gateway`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-smb-mode",
                      "code": "invalid-smb-mode",
                      "title": "invalid smb mode",
                      "status": 400,
                      "detail": "smb_mode is not direct or gateway."
                    }
                  },
                  "unknown-protection-profile-id": {
                    "summary": "`protection_profile_id` does not exist.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unknown-protection-profile-id",
                      "code": "unknown-protection-profile-id",
                      "title": "unknown protection profile id",
                      "status": 400,
                      "detail": "protection_profile_id does not exist."
                    }
                  },
                  "unknown-connector-id": {
                    "summary": "`connector_id` or one of `connector_ids` does not exist or is being removed.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unknown-connector-id",
                      "code": "unknown-connector-id",
                      "title": "unknown connector id",
                      "status": 400,
                      "detail": "connector_id or one of connector_ids does not exist or is being removed."
                    }
                  },
                  "too-many-connectors": {
                    "summary": "More than 5 hosting connectors.",
                    "value": {
                      "type": "https://cloudraw.com/problems/too-many-connectors",
                      "code": "too-many-connectors",
                      "title": "too many connectors",
                      "status": 400,
                      "detail": "More than 5 hosting connectors."
                    }
                  },
                  "invalid-remote-app": {
                    "summary": "`remote_app` on a non-`rdp` type, or `remote_app.program` is empty, longer than 260 characters or has a line break / `\"`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-remote-app",
                      "code": "invalid-remote-app",
                      "title": "invalid remote app",
                      "status": 400,
                      "detail": "remote_app on a non-rdp type, or remote_app.program is empty, longer than 260 characters or has a line break / \"."
                    }
                  },
                  "invalid-clientless": {
                    "summary": "`clientless` is not a boolean.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-clientless",
                      "code": "invalid-clientless",
                      "title": "invalid clientless",
                      "status": 400,
                      "detail": "clientless is not a boolean."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`connection-quota-reached`: The workspace has reached its plan's application limit.\n\n`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "connection-quota-reached": {
                    "summary": "The workspace has reached its plan's application limit.",
                    "value": {
                      "type": "https://cloudraw.com/problems/connection-quota-reached",
                      "code": "connection-quota-reached",
                      "title": "connection quota reached",
                      "status": 403,
                      "detail": "The workspace has reached its plan's application limit."
                    }
                  },
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`share-server-already-published`: `smb`: this file server is already published; add the share to its `shares` instead.\n\n`name-conflicts-with-a-private-network`: The name collides with a private network's internal name; choose another name.\n\n`idempotency-key-reuse`: The same `Idempotency-Key` was used with a different body within 24 hours.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "share-server-already-published": {
                    "summary": "`smb`: this file server is already published; add the share to its `shares` instead.",
                    "value": {
                      "type": "https://cloudraw.com/problems/share-server-already-published",
                      "code": "share-server-already-published",
                      "title": "share server already published",
                      "status": 409,
                      "detail": "smb: this file server is already published; add the share to its shares instead."
                    }
                  },
                  "name-conflicts-with-a-private-network": {
                    "summary": "The name collides with a private network's internal name; choose another name.",
                    "value": {
                      "type": "https://cloudraw.com/problems/name-conflicts-with-a-private-network",
                      "code": "name-conflicts-with-a-private-network",
                      "title": "name conflicts with a private network",
                      "status": 409,
                      "detail": "The name collides with a private network's internal name; choose another name."
                    }
                  },
                  "idempotency-key-reuse": {
                    "summary": "The same `Idempotency-Key` was used with a different body within 24 hours.",
                    "value": {
                      "type": "https://cloudraw.com/problems/idempotency-key-reuse",
                      "code": "idempotency-key-reuse",
                      "title": "idempotency key reuse",
                      "status": 409,
                      "detail": "The same Idempotency-Key was used with a different body within 24 hours."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`provisioning-failed`: The application could not be set up right now. Retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "provisioning-failed": {
                    "summary": "The application could not be set up right now. Retry.",
                    "value": {
                      "type": "https://cloudraw.com/problems/provisioning-failed",
                      "code": "provisioning-failed",
                      "title": "provisioning failed",
                      "status": 502,
                      "detail": "The application could not be set up right now. Retry."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        },
        "x-cloudraw-idempotent": true
      }
    },
    "/v0/tenants/{tenant_id}/connections/{connection_id}": {
      "get": {
        "tags": [
          "Apps"
        ],
        "operationId": "getConnection",
        "summary": "Get an application",
        "description": "Returns one application (same shape as in the list). Handy for polling, for example until a RemoteApp's one-time server setup reports back (`remote_app.setup.needed: false`) or browser access is ready (`browser.ready`).\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "connection_id",
            "in": "path",
            "required": true,
            "description": "Application (connection) id.",
            "schema": {
              "type": "string"
            },
            "example": "cx9m2v7d1pa"
          }
        ],
        "responses": {
          "200": {
            "description": "The application.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Connection"
                },
                "example": {
                  "id": "cx9m2v7d1pa",
                  "name": "finance-terminal",
                  "display_name": "Finance terminal",
                  "type": "rdp",
                  "host": "10.20.0.15",
                  "port": 3389,
                  "connector_id": "cn0r4w8t2kq",
                  "connector_ids": [
                    "cn0r4w8t2kq"
                  ],
                  "rdp_security": "any",
                  "rdp_domain": null,
                  "access_groups": [],
                  "clientless": true,
                  "intercept": "finance-terminal.q7x2m.cloudraw",
                  "status": {
                    "phase": "ready",
                    "observed_at": "2026-10-13T09:24:11.000Z",
                    "message": null
                  },
                  "version": 1,
                  "created_by_integrator": null,
                  "delivery": {
                    "client": true,
                    "portal": true,
                    "rbi": false,
                    "onetime_rdp": false,
                    "native": false
                  },
                  "recording": {
                    "on": false,
                    "required": false,
                    "mode": null,
                    "notice": {
                      "on": false,
                      "mandatory": true,
                      "text": "This session is recorded. What you see and do on screen is saved for security and compliance, and authorized people in your organization can watch it later.",
                      "custom": false,
                      "default_text": "This session is recorded. What you see and do on screen is saved for security and compliance, and authorized people in your organization can watch it later."
                    }
                  },
                  "redirection": {
                    "clipboard_in": true,
                    "clipboard_out": false,
                    "drives": false,
                    "printers": false,
                    "audio_out": true,
                    "mic": false,
                    "camera": false,
                    "usb": false
                  },
                  "reauth": {
                    "every_minutes": null
                  },
                  "posture": [],
                  "appfw": {
                    "mode": "off",
                    "allow": []
                  },
                  "redirection_rules": [],
                  "allowed_apps": null,
                  "remote_app": null,
                  "gateway_only": {
                    "on": false,
                    "reason": null
                  },
                  "guides": {
                    "app": {
                      "id": "app-remote-app",
                      "section": null,
                      "title": "Publish a remote desktop",
                      "url": "https://cdapi.cloudraw.com/guides/app-remote-app",
                      "pdf_url": null
                    },
                    "allowed_apps": {
                      "id": "app-allowed-apps",
                      "section": null,
                      "title": "Allowed applications",
                      "url": "https://cdapi.cloudraw.com/guides/app-allowed-apps",
                      "pdf_url": null
                    },
                    "alerts": {
                      "id": "app-allowed-apps",
                      "section": null,
                      "title": "Allowed applications",
                      "url": "https://cdapi.cloudraw.com/guides/app-allowed-apps",
                      "pdf_url": null
                    }
                  },
                  "icon": null,
                  "browser": {
                    "supported": true,
                    "ready": true,
                    "error": null,
                    "opens": "desktop"
                  },
                  "controls_enforcement": {
                    "delivery": "stored",
                    "recording": "partial:browser_sessions_only",
                    "redirection": "partial:browser_sessions_only",
                    "reauth": "stored",
                    "posture": "stored",
                    "appfw": "stored",
                    "allowed_apps": "partial:client_min_version"
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`connection-not-found`: No application with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "connection-not-found": {
                    "summary": "No application with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/connection-not-found",
                      "code": "connection-not-found",
                      "title": "connection not found",
                      "status": 404,
                      "detail": "No application with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      },
      "patch": {
        "tags": [
          "Apps"
        ],
        "operationId": "updateConnection",
        "summary": "Update an application",
        "description": "Changes an application's display name, target, hosting connectors, delivery, recording, redirection, allowed applications, RemoteApp or file-server shares. Send only what you change; nested objects (`delivery`, `recording`, `redirection`) merge key by key. Target and connector changes apply live without re-creating the application, so existing access rules keep working. The technical `name` and `intercept` never change (to rename them, delete and create again). Turning on \"recording required\" or \"browser only\" while `delivery.native` is on (or the reverse) is refused, because native Remote Desktop sessions are not recorded. All or nothing: every field is checked before anything changes, so a `4xx` answer leaves the application exactly as it was; after a `502` only a target or hosting-connector change the overlay already took stays (`GET` the application to see it). Audited. Send `If-Match: <version>` to fail with `409 version-conflict` instead of overwriting a change made in the meantime.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "connection_id",
            "in": "path",
            "required": true,
            "description": "Application (connection) id.",
            "schema": {
              "type": "string"
            },
            "example": "cx9m2v7d1pa"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConnectionUpdate"
              },
              "example": {
                "display_name": "Finance terminal (HQ)",
                "recording": {
                  "on": true,
                  "required": true
                },
                "redirection": {
                  "clipboard_out": false,
                  "drives": false
                },
                "connector_ids": [
                  "cn0r4w8t2kq",
                  "cn7k2x9m0sd"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated application.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Connection"
                },
                "example": {
                  "id": "cx9m2v7d1pa",
                  "name": "finance-terminal",
                  "display_name": "Finance terminal (HQ)",
                  "type": "rdp",
                  "host": "10.20.0.15",
                  "port": 3389,
                  "connector_id": "cn0r4w8t2kq",
                  "connector_ids": [
                    "cn0r4w8t2kq",
                    "cn7k2x9m0sd"
                  ],
                  "rdp_security": "any",
                  "rdp_domain": null,
                  "access_groups": [],
                  "clientless": true,
                  "intercept": "finance-terminal.q7x2m.cloudraw",
                  "status": {
                    "phase": "ready",
                    "observed_at": "2026-10-13T09:24:11.000Z",
                    "message": null
                  },
                  "version": 2,
                  "created_by_integrator": null,
                  "delivery": {
                    "client": true,
                    "portal": true,
                    "rbi": false,
                    "onetime_rdp": false,
                    "native": false
                  },
                  "recording": {
                    "on": true,
                    "required": true,
                    "mode": null,
                    "notice": {
                      "on": true,
                      "mandatory": true,
                      "text": "This session is recorded. What you see and do on screen is saved for security and compliance, and authorized people in your organization can watch it later.",
                      "custom": false,
                      "default_text": "This session is recorded. What you see and do on screen is saved for security and compliance, and authorized people in your organization can watch it later."
                    }
                  },
                  "redirection": {
                    "clipboard_in": true,
                    "clipboard_out": false,
                    "drives": false,
                    "printers": false,
                    "audio_out": true,
                    "mic": false,
                    "camera": false,
                    "usb": false
                  },
                  "reauth": {
                    "every_minutes": null
                  },
                  "posture": [],
                  "appfw": {
                    "mode": "off",
                    "allow": []
                  },
                  "redirection_rules": [],
                  "allowed_apps": null,
                  "remote_app": null,
                  "gateway_only": {
                    "on": false,
                    "reason": null
                  },
                  "guides": {
                    "app": {
                      "id": "app-remote-app",
                      "section": null,
                      "title": "Publish a remote desktop",
                      "url": "https://cdapi.cloudraw.com/guides/app-remote-app",
                      "pdf_url": null
                    },
                    "allowed_apps": {
                      "id": "app-allowed-apps",
                      "section": null,
                      "title": "Allowed applications",
                      "url": "https://cdapi.cloudraw.com/guides/app-allowed-apps",
                      "pdf_url": null
                    },
                    "alerts": {
                      "id": "app-allowed-apps",
                      "section": null,
                      "title": "Allowed applications",
                      "url": "https://cdapi.cloudraw.com/guides/app-allowed-apps",
                      "pdf_url": null
                    }
                  },
                  "icon": null,
                  "browser": {
                    "supported": true,
                    "ready": true,
                    "error": null,
                    "opens": "desktop"
                  },
                  "controls_enforcement": {
                    "delivery": "stored",
                    "recording": "partial:browser_sessions_only",
                    "redirection": "partial:browser_sessions_only",
                    "reauth": "stored",
                    "posture": "stored",
                    "appfw": "stored",
                    "allowed_apps": "partial:client_min_version"
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid-display-name`: `display_name` is not 1-80 characters, without `< > \" ' ` & \\` or quote marks.\n\n`invalid-delivery`: `delivery.native` is not a boolean, is set on a non-`rdp` app, or conflicts with required / browser-only recording.\n\n`invalid-recording`: `recording.notice` is not `{text}` or its text is over 300 characters; `recording.browser_only` is not a boolean or the app is not `rdp`/`ssh`/`vnc`.\n\n`invalid-redirection`: `redirection` is not an object, or has an unknown key or a non-boolean value.\n\n`invalid-redirection-rules`: `redirection_rules` is not a list of at most 20 valid rules (unknown group / person ids, bad country codes, empty `when` or `set`).\n\n`invalid-rdp-security`: `rdp_security` on a non-`rdp` app or not `any`/`nla`/`tls`/`rdp`.\n\n`invalid-rdp-domain`: `rdp_domain` on a non-`rdp` app or not a domain name like `CONTOSO`.\n\n`invalid-remote-app`: `remote_app` on a non-`rdp` app, or `remote_app.program` is invalid.\n\n`invalid-remote-app-setup-done`: `remote_app_setup_done` is not a boolean, or the app has no RemoteApp program that needs setup.\n\n`invalid-allowed-apps`: `allowed_apps` is invalid (mode, enforce, preset, more than 50 apps, or an entry's platform / name / publisher / identifier / sha256 / thumbprint / alerts).\n\n`invalid-share`: `smb`: `host` or `shares` is invalid, or `port`/`hostnames`/`ports` was sent (a file server is always on 445); or `shares` / `smb_mode` / `protection_profile_id` was sent for a non-`smb` app.\n\n`invalid-smb-mode`: `smb_mode` is not `direct` or `gateway`.\n\n`unknown-protection-profile-id`: `protection_profile_id` does not exist.\n\n`invalid-egress`: `egress`: `hostnames` (1-20 valid, non-Cloudraw names) or `ports` (1-10 ports) is invalid.\n\n`invalid-target`: `host` is empty or longer than 253 characters, or `port` is not 1-65535.\n\n`invalid-connector-ids`: `connector_ids` does not hold 1-5 connectors.\n\n`unknown-connector-id`: One of `connector_ids` does not exist or is being removed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-display-name": {
                    "summary": "`display_name` is not 1-80 characters, without `< > \" ' ` & \\` or quote marks.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-display-name",
                      "code": "invalid-display-name",
                      "title": "invalid display name",
                      "status": 400,
                      "detail": "display_name is not 1-80 characters, without < > \" '  & \\ or quote marks."
                    }
                  },
                  "invalid-delivery": {
                    "summary": "`delivery.native` is not a boolean, is set on a non-`rdp` app, or conflicts with required / browser-only recording.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-delivery",
                      "code": "invalid-delivery",
                      "title": "invalid delivery",
                      "status": 400,
                      "detail": "delivery.native is not a boolean, is set on a non-rdp app, or conflicts with required / browser-only recording."
                    }
                  },
                  "invalid-recording": {
                    "summary": "`recording.notice` is not `{text}` or its text is over 300 characters; `recording.browser_only` is not a boolean or the app is not `rdp`/`ssh`/`vnc`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-recording",
                      "code": "invalid-recording",
                      "title": "invalid recording",
                      "status": 400,
                      "detail": "recording.notice is not {text} or its text is over 300 characters; recording.browser_only is not a boolean or the app is not rdp/ssh/vnc."
                    }
                  },
                  "invalid-redirection": {
                    "summary": "`redirection` is not an object, or has an unknown key or a non-boolean value.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-redirection",
                      "code": "invalid-redirection",
                      "title": "invalid redirection",
                      "status": 400,
                      "detail": "redirection is not an object, or has an unknown key or a non-boolean value."
                    }
                  },
                  "invalid-redirection-rules": {
                    "summary": "`redirection_rules` is not a list of at most 20 valid rules (unknown group / person ids, bad country codes, empty `when` or `set`).",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-redirection-rules",
                      "code": "invalid-redirection-rules",
                      "title": "invalid redirection rules",
                      "status": 400,
                      "detail": "redirection_rules is not a list of at most 20 valid rules (unknown group / person ids, bad country codes, empty when or set)."
                    }
                  },
                  "invalid-rdp-security": {
                    "summary": "`rdp_security` on a non-`rdp` app or not `any`/`nla`/`tls`/`rdp`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-rdp-security",
                      "code": "invalid-rdp-security",
                      "title": "invalid rdp security",
                      "status": 400,
                      "detail": "rdp_security on a non-rdp app or not any/nla/tls/rdp."
                    }
                  },
                  "invalid-rdp-domain": {
                    "summary": "`rdp_domain` on a non-`rdp` app or not a domain name like `CONTOSO`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-rdp-domain",
                      "code": "invalid-rdp-domain",
                      "title": "invalid rdp domain",
                      "status": 400,
                      "detail": "rdp_domain on a non-rdp app or not a domain name like CONTOSO."
                    }
                  },
                  "invalid-remote-app": {
                    "summary": "`remote_app` on a non-`rdp` app, or `remote_app.program` is invalid.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-remote-app",
                      "code": "invalid-remote-app",
                      "title": "invalid remote app",
                      "status": 400,
                      "detail": "remote_app on a non-rdp app, or remote_app.program is invalid."
                    }
                  },
                  "invalid-remote-app-setup-done": {
                    "summary": "`remote_app_setup_done` is not a boolean, or the app has no RemoteApp program that needs setup.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-remote-app-setup-done",
                      "code": "invalid-remote-app-setup-done",
                      "title": "invalid remote app setup done",
                      "status": 400,
                      "detail": "remote_app_setup_done is not a boolean, or the app has no RemoteApp program that needs setup."
                    }
                  },
                  "invalid-allowed-apps": {
                    "summary": "`allowed_apps` is invalid (mode, enforce, preset, more than 50 apps, or an entry's platform / name / publisher / identifier / sha256 / thumbprint / alerts).",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-allowed-apps",
                      "code": "invalid-allowed-apps",
                      "title": "invalid allowed apps",
                      "status": 400,
                      "detail": "allowed_apps is invalid (mode, enforce, preset, more than 50 apps, or an entry's platform / name / publisher / identifier / sha256 / thumbprint / alerts)."
                    }
                  },
                  "invalid-share": {
                    "summary": "`smb`: `host` or `shares` is invalid, or `port`/`hostnames`/`ports` was sent (a file server is always on 445); or `shares` / `smb_mode` / `protection_profile_id` was sent for a non-`smb` app.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-share",
                      "code": "invalid-share",
                      "title": "invalid share",
                      "status": 400,
                      "detail": "smb: host or shares is invalid, or port/hostnames/ports was sent (a file server is always on 445); or shares / smb_mode / protection_profile_id was sent for a non-smb app."
                    }
                  },
                  "invalid-smb-mode": {
                    "summary": "`smb_mode` is not `direct` or `gateway`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-smb-mode",
                      "code": "invalid-smb-mode",
                      "title": "invalid smb mode",
                      "status": 400,
                      "detail": "smb_mode is not direct or gateway."
                    }
                  },
                  "unknown-protection-profile-id": {
                    "summary": "`protection_profile_id` does not exist.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unknown-protection-profile-id",
                      "code": "unknown-protection-profile-id",
                      "title": "unknown protection profile id",
                      "status": 400,
                      "detail": "protection_profile_id does not exist."
                    }
                  },
                  "invalid-egress": {
                    "summary": "`egress`: `hostnames` (1-20 valid, non-Cloudraw names) or `ports` (1-10 ports) is invalid.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-egress",
                      "code": "invalid-egress",
                      "title": "invalid egress",
                      "status": 400,
                      "detail": "egress: hostnames (1-20 valid, non-Cloudraw names) or ports (1-10 ports) is invalid."
                    }
                  },
                  "invalid-target": {
                    "summary": "`host` is empty or longer than 253 characters, or `port` is not 1-65535.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-target",
                      "code": "invalid-target",
                      "title": "invalid target",
                      "status": 400,
                      "detail": "host is empty or longer than 253 characters, or port is not 1-65535."
                    }
                  },
                  "invalid-connector-ids": {
                    "summary": "`connector_ids` does not hold 1-5 connectors.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-connector-ids",
                      "code": "invalid-connector-ids",
                      "title": "invalid connector ids",
                      "status": 400,
                      "detail": "connector_ids does not hold 1-5 connectors."
                    }
                  },
                  "unknown-connector-id": {
                    "summary": "One of `connector_ids` does not exist or is being removed.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unknown-connector-id",
                      "code": "unknown-connector-id",
                      "title": "unknown connector id",
                      "status": 400,
                      "detail": "One of connector_ids does not exist or is being removed."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`connection-not-found`: No application with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "connection-not-found": {
                    "summary": "No application with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/connection-not-found",
                      "code": "connection-not-found",
                      "title": "connection not found",
                      "status": 404,
                      "detail": "No application with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`version-conflict`: `If-Match` does not match the current `version`.\n\n`share-server-already-published`: `smb`: another application already publishes the new `host`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "version-conflict": {
                    "summary": "`If-Match` does not match the current `version`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/version-conflict",
                      "code": "version-conflict",
                      "title": "version conflict",
                      "status": 409,
                      "detail": "If-Match does not match the current version."
                    }
                  },
                  "share-server-already-published": {
                    "summary": "`smb`: another application already publishes the new `host`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/share-server-already-published",
                      "code": "share-server-already-published",
                      "title": "share server already published",
                      "status": 409,
                      "detail": "smb: another application already publishes the new host."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`allowed-apps-failed`: The allowed-applications policy could not be applied right now; nothing was changed. Retry.\n\n`provisioning-failed`: The new target or hosting connectors could not be applied right now. Retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "allowed-apps-failed": {
                    "summary": "The allowed-applications policy could not be applied right now; nothing was changed. Retry.",
                    "value": {
                      "type": "https://cloudraw.com/problems/allowed-apps-failed",
                      "code": "allowed-apps-failed",
                      "title": "allowed apps failed",
                      "status": 502,
                      "detail": "The allowed-applications policy could not be applied right now; nothing was changed. Retry."
                    }
                  },
                  "provisioning-failed": {
                    "summary": "The new target or hosting connectors could not be applied right now. Retry.",
                    "value": {
                      "type": "https://cloudraw.com/problems/provisioning-failed",
                      "code": "provisioning-failed",
                      "title": "provisioning failed",
                      "status": 502,
                      "detail": "The new target or hosting connectors could not be applied right now. Retry."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      },
      "delete": {
        "tags": [
          "Apps"
        ],
        "operationId": "deleteConnection",
        "summary": "Delete an application",
        "description": "Unpublishes the application. Every access rule that targets it is deleted too, and its active sessions are ended. Cannot be undone. Audited (one row per removed rule and ended session). The answer is a finished task.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "connection_id",
            "in": "path",
            "required": true,
            "description": "Application (connection) id.",
            "schema": {
              "type": "string"
            },
            "example": "cx9m2v7d1pa"
          }
        ],
        "responses": {
          "202": {
            "description": "Deleted (the task is already `done`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                },
                "example": {
                  "id": "task_8k2m0x9s1d",
                  "tenant_id": "tq7x2m9k4ab",
                  "state": "done",
                  "result_uri": null,
                  "error": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`connection-not-found`: No application with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "connection-not-found": {
                    "summary": "No application with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/connection-not-found",
                      "code": "connection-not-found",
                      "title": "connection not found",
                      "status": 404,
                      "detail": "No application with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`delete-failed`: The application could not be removed right now. Retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "delete-failed": {
                    "summary": "The application could not be removed right now. Retry.",
                    "value": {
                      "type": "https://cloudraw.com/problems/delete-failed",
                      "code": "delete-failed",
                      "title": "delete failed",
                      "status": 502,
                      "detail": "The application could not be removed right now. Retry."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/connectors": {
      "get": {
        "tags": [
          "Connectors"
        ],
        "operationId": "listConnectors",
        "summary": "List connectors",
        "description": "Returns every connector of the workspace with its online state, version, update state, trust state and a hosting summary. Online state is refreshed on each call. The full public IP is never included for API tokens; `public_ip_masked` is.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "responses": {
          "200": {
            "description": "All connectors (not paginated).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnectorList"
                },
                "example": {
                  "items": [
                    {
                      "id": "cn0r4w8t2kq",
                      "name": "hq-server-1",
                      "platform": "windows",
                      "online": true,
                      "enrolled": true,
                      "hostname": "HQ-APP01",
                      "os": "Windows",
                      "os_version": "10.0.20348",
                      "last_seen": "2026-10-13T09:24:11.000Z",
                      "sw_version": "1.18.7-b11c",
                      "tunnel_version": "1.18.7",
                      "pending_removal": null,
                      "public_ip": null,
                      "public_ip_masked": "203.0.113.x",
                      "public_ip_version": 4,
                      "public_ip_at": "2026-10-13T09:15:02.000Z",
                      "public_ip_source": "updater-check",
                      "update": {
                        "mode": "auto_window",
                        "mode_source": "workspace",
                        "mode_override": null,
                        "mode_override_by": null,
                        "mode_override_at": null,
                        "rollout": null,
                        "current_version": "1.18.7-b11c",
                        "build_known": true,
                        "available_version": null,
                        "previous_version": "1.18.7-b9c",
                        "requested_at": null,
                        "applied_at": "2026-10-11T02:14:09.000Z",
                        "last_check_at": "2026-10-13T09:15:02.000Z",
                        "last": {
                          "ok": true,
                          "from": "1.18.7-b9c",
                          "to": "1.18.7-b11c",
                          "message": "updated",
                          "at": "2026-10-11T02:14:09.000Z"
                        },
                        "updater": true,
                        "token_rotated_at": "2026-10-02T11:40:00.000Z",
                        "paused": null,
                        "last_paused": null,
                        "updater_state": "ok",
                        "last_reject_at": null
                      },
                      "remote_app_helper": {
                        "enabled": true,
                        "last_seen": "2026-10-13T09:10:00.000Z",
                        "programs_listed_at": "2026-10-12T16:02:00.000Z"
                      },
                      "guides": {
                        "install": {
                          "id": "connector-windows",
                          "section": null,
                          "title": "Install a connector on Windows",
                          "url": "https://cdapi.cloudraw.com/guides/connector-windows",
                          "pdf_url": "https://cdapi.cloudraw.com/guides/connector-windows.pdf"
                        },
                        "updates": {
                          "id": "connector-updates",
                          "section": null,
                          "title": "Connector updates",
                          "url": "https://cdapi.cloudraw.com/guides/connector-updates",
                          "pdf_url": "https://cdapi.cloudraw.com/guides/connector-updates.pdf"
                        },
                        "high_availability": {
                          "id": "connector-ha",
                          "section": null,
                          "title": "Connector high availability",
                          "url": "https://cdapi.cloudraw.com/guides/connector-ha",
                          "pdf_url": "https://cdapi.cloudraw.com/guides/connector-ha.pdf"
                        },
                        "remoteapp_helper": {
                          "id": "connector-remoteapp-helper",
                          "section": null,
                          "title": "RemoteApp helper",
                          "url": "https://cdapi.cloudraw.com/guides/connector-remoteapp-helper",
                          "pdf_url": "https://cdapi.cloudraw.com/guides/connector-remoteapp-helper.pdf"
                        }
                      },
                      "status": {
                        "phase": "ready",
                        "observed_at": "2026-10-13T09:24:11.000Z",
                        "message": null
                      },
                      "version": 14,
                      "created_by_integrator": null,
                      "claim_burned_at": null,
                      "bitlocker": null,
                      "short_id": "w8t2kq",
                      "identity_id": "Xk2m9QvR1",
                      "hostname_shared": false,
                      "hostname_shared_with": [],
                      "trust": {
                        "state": "trusted",
                        "reason": "connector trusted",
                        "source": "default",
                        "evaluated_at": "2026-10-13T09:24:11.000Z",
                        "manual": null,
                        "approved": false
                      },
                      "hosting_summary": {
                        "expected": 3,
                        "hosted": 3,
                        "missing": 0,
                        "partial": 0,
                        "checked_at": "2026-10-13T09:23:40.000Z"
                      }
                    }
                  ],
                  "next_page": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      },
      "post": {
        "tags": [
          "Connectors"
        ],
        "operationId": "createConnector",
        "summary": "Create a connector",
        "description": "Creates a connector record and returns how to install it. The connector does nothing until you run the install on a machine in your network; it then connects outbound only (no inbound ports).\n\n**Install flow, by platform**\n- **Windows** (`platform: windows`): run `install_command` in an Administrator PowerShell on the host. It downloads the install script through the short `claim_url` and installs the connector as a service with automatic updates. Where PowerShell scripts are blocked by policy, download the signed setup program from `installer.url` (check `installer.sha256`) and run `installer.silent_command` (`/S /CODE=<claim_code>`). The code is single use for the setup program.\n- **Linux** (`linux`, `deb`, `rpm`): run `install_command` (`curl -fsSL <claim_url> | sh`) as a sudo-capable user on an x86_64 machine.\n- **Docker** (`docker`, the default): `install_command` is the same Linux one-liner; `alt_install.docker` is a `docker run` command (host networking, restart unless-stopped) with the enrolment token inline.\n\nThe claim link is valid 24 hours and at most 20 fetches, and stops working once the connector has installed. The enrolment token (`enrollment_jwt`) is single use and valid 7 days (`expires_at`); to get a fresh link later, call `POST …/connectors/{connector_id}/install`. Watch `GET …/connectors` until `online` is true. Audited.\n\n**Token:** full access · **Created by:** owner\n\n**Idempotency:** send `Idempotency-Key`. The answer carries a secret shown once: a retry with the same key answers `409 already-issued` instead of the secret.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Connector name. Lower-cased; anything other than a-z and 0-9 becomes a dash; cut to 40 characters."
                  },
                  "platform": {
                    "type": "string",
                    "enum": [
                      "docker",
                      "linux",
                      "deb",
                      "rpm",
                      "windows"
                    ],
                    "description": "Where it will run. Default `docker`."
                  }
                },
                "required": [
                  "name"
                ]
              },
              "example": {
                "name": "Branch Linux 1",
                "platform": "linux"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created. The install values are shown once (the answer is not cached and is not replayed).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnectorInstall"
                },
                "example": {
                  "connector": {
                    "id": "cn5t8w2k0pd",
                    "name": "branch-linux-1",
                    "platform": "linux",
                    "online": false,
                    "enrolled": false,
                    "hostname": null,
                    "os": null,
                    "os_version": null,
                    "last_seen": null,
                    "sw_version": null,
                    "tunnel_version": null,
                    "pending_removal": null,
                    "public_ip": null,
                    "public_ip_masked": null,
                    "public_ip_version": null,
                    "public_ip_at": null,
                    "public_ip_source": null,
                    "update": {
                      "mode": "auto_window",
                      "mode_source": "workspace",
                      "mode_override": null,
                      "mode_override_by": null,
                      "mode_override_at": null,
                      "rollout": null,
                      "current_version": null,
                      "build_known": false,
                      "available_version": null,
                      "previous_version": null,
                      "requested_at": null,
                      "applied_at": null,
                      "last_check_at": null,
                      "last": {},
                      "updater": true,
                      "token_rotated_at": null,
                      "paused": null,
                      "last_paused": null,
                      "updater_state": "never_checked",
                      "last_reject_at": null
                    },
                    "remote_app_helper": {
                      "enabled": true,
                      "last_seen": null,
                      "programs_listed_at": null
                    },
                    "guides": {
                      "install": {
                        "id": "connector-linux",
                        "section": null,
                        "title": "Install a connector on Linux",
                        "url": "https://cdapi.cloudraw.com/guides/connector-linux",
                        "pdf_url": "https://cdapi.cloudraw.com/guides/connector-linux.pdf"
                      },
                      "updates": {
                        "id": "connector-updates",
                        "section": null,
                        "title": "Connector updates",
                        "url": "https://cdapi.cloudraw.com/guides/connector-updates",
                        "pdf_url": "https://cdapi.cloudraw.com/guides/connector-updates.pdf"
                      },
                      "high_availability": {
                        "id": "connector-ha",
                        "section": null,
                        "title": "Connector high availability",
                        "url": "https://cdapi.cloudraw.com/guides/connector-ha",
                        "pdf_url": "https://cdapi.cloudraw.com/guides/connector-ha.pdf"
                      },
                      "remoteapp_helper": {
                        "id": "connector-remoteapp-helper",
                        "section": null,
                        "title": "RemoteApp helper",
                        "url": "https://cdapi.cloudraw.com/guides/connector-remoteapp-helper",
                        "pdf_url": "https://cdapi.cloudraw.com/guides/connector-remoteapp-helper.pdf"
                      }
                    },
                    "status": {
                      "phase": "pending",
                      "observed_at": null,
                      "message": "waiting for connector to come online"
                    },
                    "version": 1,
                    "created_by_integrator": null,
                    "claim_burned_at": null,
                    "bitlocker": null
                  },
                  "install_command": "curl -fsSL https://cdapi.cloudraw.com/c/p2x8m0k4d9s1q7wa | sh",
                  "claim_url": "https://cdapi.cloudraw.com/c/p2x8m0k4d9s1q7wa",
                  "claim_expires_at": "2026-10-14T09:24:11.000Z",
                  "claim_code": null,
                  "installer": null,
                  "install_steps": [
                    {
                      "title": "Install the Cloudraw Connector",
                      "command": "curl -fsSL https://cdapi.cloudraw.com/c/p2x8m0k4d9s1q7wa | sh",
                      "note": "One command on any Linux x86_64 machine in your network. Outbound-only. The short link enrolls this connector and expires soon — run it now.",
                      "verify": "connector_online"
                    }
                  ],
                  "alt_install": {
                    "docker": "docker run -d --name cloudraw-connector-branch-linux-1 --restart unless-stopped --network host -e …='<enrolment token>' … run-host"
                  },
                  "setup_url": null,
                  "enrollment_jwt": "eyJhbGciOiJSUzI1NiIsImtpZCI6Ii4uLiJ9.eyJleHAiOjE3NjA5NTE0NTF9.c2lnbmF0dXJl",
                  "expires_at": "2026-10-20T09:24:11.000Z"
                }
              }
            }
          },
          "400": {
            "description": "`name-required`: `name` is missing or empty.\n\n`invalid-platform`: `platform` is not docker, linux, deb, rpm or windows.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "name-required": {
                    "summary": "`name` is missing or empty.",
                    "value": {
                      "type": "https://cloudraw.com/problems/name-required",
                      "code": "name-required",
                      "title": "name required",
                      "status": 400,
                      "detail": "name is missing or empty."
                    }
                  },
                  "invalid-platform": {
                    "summary": "`platform` is not docker, linux, deb, rpm or windows.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-platform",
                      "code": "invalid-platform",
                      "title": "invalid platform",
                      "status": 400,
                      "detail": "platform is not docker, linux, deb, rpm or windows."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`connector-quota-reached`: The workspace already has as many connectors as its plan allows.\n\n`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "connector-quota-reached": {
                    "summary": "The workspace already has as many connectors as its plan allows.",
                    "value": {
                      "type": "https://cloudraw.com/problems/connector-quota-reached",
                      "code": "connector-quota-reached",
                      "title": "connector quota reached",
                      "status": 403,
                      "detail": "The workspace already has as many connectors as its plan allows."
                    }
                  },
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`name-pending-removal`: A removed connector with this name can still be restored. Restore it in the console, or pick another name.\n\n`idempotency-key-reuse`: The same `Idempotency-Key` was used with a different body within 24 hours.\n\n`already-issued`: This `Idempotency-Key` already created a secret; it is shown only once. Retry with a new key.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "name-pending-removal": {
                    "summary": "A removed connector with this name can still be restored. Restore it in the console, or pick another name.",
                    "value": {
                      "type": "https://cloudraw.com/problems/name-pending-removal",
                      "code": "name-pending-removal",
                      "title": "name pending removal",
                      "status": 409,
                      "detail": "A removed connector with this name can still be restored. Restore it in the console, or pick another name."
                    }
                  },
                  "idempotency-key-reuse": {
                    "summary": "The same `Idempotency-Key` was used with a different body within 24 hours.",
                    "value": {
                      "type": "https://cloudraw.com/problems/idempotency-key-reuse",
                      "code": "idempotency-key-reuse",
                      "title": "idempotency key reuse",
                      "status": 409,
                      "detail": "The same Idempotency-Key was used with a different body within 24 hours."
                    }
                  },
                  "already-issued": {
                    "summary": "This `Idempotency-Key` already created a secret; it is shown only once. Retry with a new key.",
                    "value": {
                      "type": "https://cloudraw.com/problems/already-issued",
                      "code": "already-issued",
                      "title": "already issued",
                      "status": 409,
                      "detail": "This Idempotency-Key already created a secret; it is shown only once. Retry with a new key."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`provisioning-failed`: Cloudraw could not create the connector identity. Nothing usable was created; retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "provisioning-failed": {
                    "summary": "Cloudraw could not create the connector identity. Nothing usable was created; retry.",
                    "value": {
                      "type": "https://cloudraw.com/problems/provisioning-failed",
                      "code": "provisioning-failed",
                      "title": "provisioning failed",
                      "status": 502,
                      "detail": "Cloudraw could not create the connector identity. Nothing usable was created; retry."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        },
        "x-cloudraw-idempotent": "secret"
      }
    },
    "/v0/tenants/{tenant_id}/connectors/{connector_id}": {
      "patch": {
        "tags": [
          "Connectors"
        ],
        "operationId": "updateConnector",
        "summary": "Change connector settings",
        "description": "Changes the settings an admin may change on a connector. Today that is only the RemoteApp helper switch (`remote_app_helper`); other fields in the body are ignored. Removing, disabling, enabling or approving a connector is not possible with an API token: those need a second-factor check by an admin in the Cloudraw console. Audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "connector_id",
            "in": "path",
            "required": true,
            "description": "Connector id (from `GET …/connectors`).",
            "schema": {
              "type": "string"
            },
            "example": "cn0r4w8t2kq"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "remote_app_helper": {
                    "type": "boolean",
                    "description": "Turn the RemoteApp helper of a Windows connector on or off."
                  }
                }
              },
              "example": {
                "remote_app_helper": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The connector after the change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Connector"
                },
                "example": {
                  "id": "cn0r4w8t2kq",
                  "name": "hq-server-1",
                  "platform": "windows",
                  "online": true,
                  "enrolled": true,
                  "hostname": "HQ-APP01",
                  "os": "Windows",
                  "os_version": "10.0.20348",
                  "last_seen": "2026-10-13T09:24:11.000Z",
                  "sw_version": "1.18.7-b11c",
                  "tunnel_version": "1.18.7",
                  "pending_removal": null,
                  "public_ip": null,
                  "public_ip_masked": "203.0.113.x",
                  "public_ip_version": 4,
                  "public_ip_at": "2026-10-13T09:15:02.000Z",
                  "public_ip_source": "updater-check",
                  "update": {
                    "mode": "auto_window",
                    "mode_source": "workspace",
                    "mode_override": null,
                    "mode_override_by": null,
                    "mode_override_at": null,
                    "rollout": null,
                    "current_version": "1.18.7-b11c",
                    "build_known": true,
                    "available_version": null,
                    "previous_version": "1.18.7-b9c",
                    "requested_at": null,
                    "applied_at": "2026-10-11T02:14:09.000Z",
                    "last_check_at": "2026-10-13T09:15:02.000Z",
                    "last": {
                      "ok": true,
                      "from": "1.18.7-b9c",
                      "to": "1.18.7-b11c",
                      "message": "updated",
                      "at": "2026-10-11T02:14:09.000Z"
                    },
                    "updater": true,
                    "token_rotated_at": "2026-10-02T11:40:00.000Z",
                    "paused": null,
                    "last_paused": null,
                    "updater_state": "ok",
                    "last_reject_at": null
                  },
                  "remote_app_helper": {
                    "enabled": false,
                    "last_seen": "2026-10-13T09:10:00.000Z",
                    "programs_listed_at": "2026-10-12T16:02:00.000Z"
                  },
                  "guides": {
                    "install": {
                      "id": "connector-windows",
                      "section": null,
                      "title": "Install a connector on Windows",
                      "url": "https://cdapi.cloudraw.com/guides/connector-windows",
                      "pdf_url": "https://cdapi.cloudraw.com/guides/connector-windows.pdf"
                    },
                    "updates": {
                      "id": "connector-updates",
                      "section": null,
                      "title": "Connector updates",
                      "url": "https://cdapi.cloudraw.com/guides/connector-updates",
                      "pdf_url": "https://cdapi.cloudraw.com/guides/connector-updates.pdf"
                    },
                    "high_availability": {
                      "id": "connector-ha",
                      "section": null,
                      "title": "Connector high availability",
                      "url": "https://cdapi.cloudraw.com/guides/connector-ha",
                      "pdf_url": "https://cdapi.cloudraw.com/guides/connector-ha.pdf"
                    },
                    "remoteapp_helper": {
                      "id": "connector-remoteapp-helper",
                      "section": null,
                      "title": "RemoteApp helper",
                      "url": "https://cdapi.cloudraw.com/guides/connector-remoteapp-helper",
                      "pdf_url": "https://cdapi.cloudraw.com/guides/connector-remoteapp-helper.pdf"
                    }
                  },
                  "status": {
                    "phase": "ready",
                    "observed_at": "2026-10-13T09:24:11.000Z",
                    "message": null
                  },
                  "version": 14,
                  "created_by_integrator": null,
                  "claim_burned_at": null,
                  "bitlocker": null,
                  "short_id": "w8t2kq",
                  "identity_id": "Xk2m9QvR1",
                  "hostname_shared": false,
                  "hostname_shared_with": [],
                  "trust": {
                    "state": "trusted",
                    "reason": "connector trusted",
                    "source": "default",
                    "evaluated_at": "2026-10-13T09:24:11.000Z",
                    "manual": null,
                    "approved": false
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid-remote-app-helper`: `remote_app_helper` is not true or false.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-remote-app-helper": {
                    "summary": "`remote_app_helper` is not true or false.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-remote-app-helper",
                      "code": "invalid-remote-app-helper",
                      "title": "invalid remote app helper",
                      "status": 400,
                      "detail": "remote_app_helper is not true or false."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`connector-not-found`: No connector with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "connector-not-found": {
                    "summary": "No connector with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/connector-not-found",
                      "code": "connector-not-found",
                      "title": "connector not found",
                      "status": 404,
                      "detail": "No connector with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/connectors/{connector_id}/enable-updates": {
      "post": {
        "tags": [
          "Connector updates"
        ],
        "operationId": "enableConnectorUpdates",
        "summary": "Turn on automatic updates",
        "description": "For a connector installed without the updater (its \"Update now\" never arrives): issues a new update token and returns a command to run once on the connector host. The command adds the updater, which checks in at once; the running connector is not touched. The previous update token stops working, so only run the newest command. Refused while an updater is already checking in. Audited.\n\n**Token:** full access · **Created by:** owner\n\n**Idempotency:** send `Idempotency-Key`. The answer carries a secret shown once: a retry with the same key answers `409 already-issued` instead of the secret.\n\n**Rate limit:** At most 10 connector commands (Update now, Turn on automatic updates, Pause, Resume) per 10 minutes per workspace, counted across every admin, integration and API token. A refused or failed command does not use up the budget.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "connector_id",
            "in": "path",
            "required": true,
            "description": "Connector id (from `GET …/connectors`).",
            "schema": {
              "type": "string"
            },
            "example": "cn0r4w8t2kq"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "201": {
            "description": "The command. Shown once (it carries the update token; not cached, not replayed).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnectorUpdaterCommand"
                },
                "example": {
                  "connector_id": "cn0r4w8t2kq",
                  "os": "Linux",
                  "command": "curl -fsSL 'https://cdapi.cloudraw.com/connector/install.sh' | sudo bash -s -- --updater-only 'tq7x2m9k4ab' 'cn0r4w8t2kq' 'cut_…'",
                  "windows": "powershell … -Tenant '…' -Connector '…' -UpdateToken 'cut_…'",
                  "linux": "curl -fsSL 'https://cdapi.cloudraw.com/connector/install.sh' | sudo bash -s -- --updater-only 'tq7x2m9k4ab' 'cn0r4w8t2kq' 'cut_…'",
                  "note": "Shown once. Run it on the connector host (Windows: an Administrator PowerShell). It adds the updater and runs a check at once; a pending \"Update now\" is applied within a few minutes. The connector itself keeps running."
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`connector-not-found`: No connector with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "connector-not-found": {
                    "summary": "No connector with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/connector-not-found",
                      "code": "connector-not-found",
                      "title": "connector not found",
                      "status": 404,
                      "detail": "No connector with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`updates-paused`: Automatic updates of this connector are paused. Resume them first.\n\n`updater-already-active`: The connector's updater checked in within the last 2 hours; \"Update now\" works without this.\n\n`idempotency-key-reuse`: The same `Idempotency-Key` was used with a different body within 24 hours.\n\n`already-issued`: This `Idempotency-Key` already created a secret; it is shown only once. Retry with a new key.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "updates-paused": {
                    "summary": "Automatic updates of this connector are paused. Resume them first.",
                    "value": {
                      "type": "https://cloudraw.com/problems/updates-paused",
                      "code": "updates-paused",
                      "title": "updates paused",
                      "status": 409,
                      "detail": "Automatic updates of this connector are paused. Resume them first."
                    }
                  },
                  "updater-already-active": {
                    "summary": "The connector's updater checked in within the last 2 hours; \"Update now\" works without this.",
                    "value": {
                      "type": "https://cloudraw.com/problems/updater-already-active",
                      "code": "updater-already-active",
                      "title": "updater already active",
                      "status": 409,
                      "detail": "The connector's updater checked in within the last 2 hours; \"Update now\" works without this."
                    }
                  },
                  "idempotency-key-reuse": {
                    "summary": "The same `Idempotency-Key` was used with a different body within 24 hours.",
                    "value": {
                      "type": "https://cloudraw.com/problems/idempotency-key-reuse",
                      "code": "idempotency-key-reuse",
                      "title": "idempotency key reuse",
                      "status": 409,
                      "detail": "The same Idempotency-Key was used with a different body within 24 hours."
                    }
                  },
                  "already-issued": {
                    "summary": "This `Idempotency-Key` already created a secret; it is shown only once. Retry with a new key.",
                    "value": {
                      "type": "https://cloudraw.com/problems/already-issued",
                      "code": "already-issued",
                      "title": "already issued",
                      "status": 409,
                      "detail": "This Idempotency-Key already created a secret; it is shown only once. Retry with a new key."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`too-many-connector-commands`: More than 10 connector commands in 10 minutes in this workspace. Wait `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "too-many-connector-commands": {
                    "summary": "More than 10 connector commands in 10 minutes in this workspace. Wait `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/too-many-connector-commands",
                      "code": "too-many-connector-commands",
                      "title": "too many connector commands",
                      "status": 429,
                      "detail": "More than 10 connector commands in 10 minutes in this workspace. Wait Retry-After seconds."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        },
        "x-cloudraw-rate-limit": "At most 10 connector commands (Update now, Turn on automatic updates, Pause, Resume) per 10 minutes per workspace, counted across every admin, integration and API token. A refused or failed command does not use up the budget.",
        "x-cloudraw-idempotent": "secret"
      }
    },
    "/v0/tenants/{tenant_id}/connectors/{connector_id}/hosting": {
      "get": {
        "tags": [
          "Connectors"
        ],
        "operationId": "getConnectorHosting",
        "summary": "Check what a connector hosts",
        "description": "Compares what the connector should host (the apps, private networks and directory link assigned to it) with what it really holds on the Cloudraw edge, per edge location. Use it when a connector shows online but an app does not open: `missing` lists items it does not host, `partial` ones held on fewer edge locations than expected. Results are cached about 30 seconds.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "connector_id",
            "in": "path",
            "required": true,
            "description": "Connector id (from `GET …/connectors`).",
            "schema": {
              "type": "string"
            },
            "example": "cn0r4w8t2kq"
          },
          {
            "name": "refresh",
            "in": "query",
            "required": false,
            "description": "`1` = read fresh data now instead of the cache (at most every 5 seconds).",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Expected vs real hosting.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnectorHosting"
                },
                "example": {
                  "connector_id": "cn0r4w8t2kq",
                  "online": true,
                  "enrolled": true,
                  "expected_services": [
                    {
                      "service": "tq7x2m9k4ab.erp-web",
                      "kind": "connection",
                      "display_name": "ERP (web)",
                      "type": "https",
                      "ha_hosts": 1,
                      "connection_id": "cx9m2v7d1pa",
                      "link_hint": "connections/cx9m2v7d1pa",
                      "id": "cx9m2v7d1pa",
                      "name": "ERP (web)"
                    }
                  ],
                  "hosted": [
                    {
                      "service": "tq7x2m9k4ab.erp-web",
                      "kind": "connection",
                      "display_name": "ERP (web)",
                      "type": "https",
                      "ha_hosts": 1,
                      "connection_id": "cx9m2v7d1pa",
                      "link_hint": "connections/cx9m2v7d1pa",
                      "id": "cx9m2v7d1pa",
                      "name": "ERP (web)",
                      "terminators": [
                        {
                          "router": "edge-1",
                          "precedence": "default",
                          "cost": 0,
                          "created_at": "2026-10-13T06:00:00.000Z"
                        },
                        {
                          "router": "edge-2",
                          "precedence": "default",
                          "cost": 0,
                          "created_at": "2026-10-13T06:00:01.000Z"
                        }
                      ],
                      "partial": true
                    }
                  ],
                  "missing": [],
                  "missing_details": [],
                  "summary": {
                    "expected": 1,
                    "hosted": 1,
                    "missing": 0,
                    "partial": 1,
                    "terminators_total": 2,
                    "expected_terminators_per_service": 3,
                    "routers": [
                      {
                        "router": "edge-1",
                        "connected": true,
                        "terminators": 1
                      },
                      {
                        "router": "edge-2",
                        "connected": true,
                        "terminators": 1
                      },
                      {
                        "router": "edge-3",
                        "connected": true,
                        "terminators": 0
                      }
                    ]
                  },
                  "checked_at": "2026-10-13T09:24:05.000Z"
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`connector-not-found`: No connector with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "connector-not-found": {
                    "summary": "No connector with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/connector-not-found",
                      "code": "connector-not-found",
                      "title": "connector not found",
                      "status": 404,
                      "detail": "No connector with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`hosting-unavailable`: Hosting could not be read right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "hosting-unavailable": {
                    "summary": "Hosting could not be read right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/hosting-unavailable",
                      "code": "hosting-unavailable",
                      "title": "hosting unavailable",
                      "status": 503,
                      "detail": "Hosting could not be read right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/connectors/{connector_id}/install": {
      "get": {
        "tags": [
          "Connectors"
        ],
        "operationId": "getConnectorInstall",
        "summary": "Get install details of a connector",
        "description": "For a connector that has not installed yet: returns the connector, when its enrolment token expires and the Windows setup program, but no install command or code (`install_command`, `claim_url`, `claim_code` and `enrollment_jwt` are null). Use `POST` on the same path (`reveal_with`) to get a fresh install link. A connector that already installed answers 409: if it is offline, fix its connectivity; reinstalling will not help.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "connector_id",
            "in": "path",
            "required": true,
            "description": "Connector id (from `GET …/connectors`).",
            "schema": {
              "type": "string"
            },
            "example": "cn0r4w8t2kq"
          }
        ],
        "responses": {
          "200": {
            "description": "Install metadata without secrets.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnectorInstall"
                },
                "example": {
                  "connector": {
                    "id": "cn0r4w8t2kq",
                    "name": "hq-server-2",
                    "platform": "windows",
                    "online": false,
                    "enrolled": false,
                    "hostname": null,
                    "os": null,
                    "os_version": null,
                    "last_seen": null,
                    "sw_version": null,
                    "tunnel_version": null,
                    "pending_removal": null,
                    "public_ip": null,
                    "public_ip_masked": null,
                    "public_ip_version": null,
                    "public_ip_at": null,
                    "public_ip_source": null,
                    "update": {
                      "mode": "auto_window",
                      "mode_source": "workspace",
                      "mode_override": null,
                      "mode_override_by": null,
                      "mode_override_at": null,
                      "rollout": null,
                      "current_version": null,
                      "build_known": false,
                      "available_version": null,
                      "previous_version": null,
                      "requested_at": null,
                      "applied_at": null,
                      "last_check_at": null,
                      "last": {},
                      "updater": true,
                      "token_rotated_at": null,
                      "paused": null,
                      "last_paused": null,
                      "updater_state": "never_checked",
                      "last_reject_at": null
                    },
                    "remote_app_helper": {
                      "enabled": true,
                      "last_seen": null,
                      "programs_listed_at": null
                    },
                    "guides": {
                      "install": {
                        "id": "connector-windows",
                        "section": null,
                        "title": "Install a connector on Windows",
                        "url": "https://cdapi.cloudraw.com/guides/connector-windows",
                        "pdf_url": "https://cdapi.cloudraw.com/guides/connector-windows.pdf"
                      },
                      "updates": {
                        "id": "connector-updates",
                        "section": null,
                        "title": "Connector updates",
                        "url": "https://cdapi.cloudraw.com/guides/connector-updates",
                        "pdf_url": "https://cdapi.cloudraw.com/guides/connector-updates.pdf"
                      },
                      "high_availability": {
                        "id": "connector-ha",
                        "section": null,
                        "title": "Connector high availability",
                        "url": "https://cdapi.cloudraw.com/guides/connector-ha",
                        "pdf_url": "https://cdapi.cloudraw.com/guides/connector-ha.pdf"
                      },
                      "remoteapp_helper": {
                        "id": "connector-remoteapp-helper",
                        "section": null,
                        "title": "RemoteApp helper",
                        "url": "https://cdapi.cloudraw.com/guides/connector-remoteapp-helper",
                        "pdf_url": "https://cdapi.cloudraw.com/guides/connector-remoteapp-helper.pdf"
                      }
                    },
                    "status": {
                      "phase": "pending",
                      "observed_at": null,
                      "message": "waiting for connector to come online"
                    },
                    "version": 1,
                    "created_by_integrator": null,
                    "claim_burned_at": null,
                    "bitlocker": null
                  },
                  "install_command": null,
                  "claim_url": null,
                  "claim_expires_at": null,
                  "claim_code": null,
                  "installer": {
                    "url": "https://cdapi.cloudraw.com/connector/staged/cloudraw-connector-setup-1.18.7-b11c.exe",
                    "file_name": "cloudraw-connector-setup-1.18.7-b11c.exe",
                    "sha256": "9f2c4e1a7b3d5f8e0a6c2b4d9e1f3a5c7b9d0e2f4a6c8b0d2e4f6a8c0b2d4e6f",
                    "signer": "Cloudraw Ltd",
                    "version": "1.18.7-b11c",
                    "silent_command": null,
                    "silent_command_file": null
                  },
                  "install_steps": [
                    {
                      "title": "Install the Cloudraw Connector",
                      "command": null,
                      "note": "Reveal the install command to get a fresh short install link.",
                      "verify": "connector_online"
                    }
                  ],
                  "setup_url": null,
                  "enrollment_jwt": null,
                  "expires_at": "2026-10-19T15:02:00.000Z",
                  "reveal_with": {
                    "method": "POST",
                    "path": "/v0/tenants/tq7x2m9k4ab/connectors/cn0r4w8t2kq/install"
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`connector-not-found`: No connector with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "connector-not-found": {
                    "summary": "No connector with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/connector-not-found",
                      "code": "connector-not-found",
                      "title": "connector not found",
                      "status": 404,
                      "detail": "No connector with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`already-installed`: The connector has already installed (its enrolment token is spent).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "already-installed": {
                    "summary": "The connector has already installed (its enrolment token is spent).",
                    "value": {
                      "type": "https://cloudraw.com/problems/already-installed",
                      "code": "already-installed",
                      "title": "already installed",
                      "status": 409,
                      "detail": "The connector has already installed (its enrolment token is spent)."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`lookup-failed`: Cloudraw could not read the connector identity; retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "lookup-failed": {
                    "summary": "Cloudraw could not read the connector identity; retry.",
                    "value": {
                      "type": "https://cloudraw.com/problems/lookup-failed",
                      "code": "lookup-failed",
                      "title": "lookup failed",
                      "status": 502,
                      "detail": "Cloudraw could not read the connector identity; retry."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      },
      "post": {
        "tags": [
          "Connectors"
        ],
        "operationId": "createConnectorInstallCode",
        "summary": "Get a new install command",
        "description": "For a connector that has not installed yet: makes a fresh short install link (24 hours) and a fresh update token, and returns the install command for its platform: the PowerShell one-liner plus `claim_code` / `installer` for Windows, `curl … | sh` for Linux, and a `docker run` command with the enrolment token inline for Docker. Any earlier install link of this connector stops working (one live code per connector); an install that already started with an earlier link still completes. The enrolment token keeps its original expiry (`expires_at`). Audited.\n\n**Token:** full access · **Created by:** owner\n\n**Idempotency:** send `Idempotency-Key`. The answer carries a secret shown once: a retry with the same key answers `409 already-issued` instead of the secret.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "connector_id",
            "in": "path",
            "required": true,
            "description": "Connector id (from `GET …/connectors`).",
            "schema": {
              "type": "string"
            },
            "example": "cn0r4w8t2kq"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "A fresh install command. Shown once (not cached, not replayed).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnectorInstall"
                },
                "example": {
                  "connector": {
                    "id": "cn0r4w8t2kq",
                    "name": "hq-server-2",
                    "platform": "windows",
                    "online": false,
                    "enrolled": false,
                    "hostname": null,
                    "os": null,
                    "os_version": null,
                    "last_seen": null,
                    "sw_version": null,
                    "tunnel_version": null,
                    "pending_removal": null,
                    "public_ip": null,
                    "public_ip_masked": null,
                    "public_ip_version": null,
                    "public_ip_at": null,
                    "public_ip_source": null,
                    "update": {
                      "mode": "auto_window",
                      "mode_source": "workspace",
                      "mode_override": null,
                      "mode_override_by": null,
                      "mode_override_at": null,
                      "rollout": null,
                      "current_version": null,
                      "build_known": false,
                      "available_version": null,
                      "previous_version": null,
                      "requested_at": null,
                      "applied_at": null,
                      "last_check_at": null,
                      "last": {},
                      "updater": true,
                      "token_rotated_at": null,
                      "paused": null,
                      "last_paused": null,
                      "updater_state": "never_checked",
                      "last_reject_at": null
                    },
                    "remote_app_helper": {
                      "enabled": true,
                      "last_seen": null,
                      "programs_listed_at": null
                    },
                    "guides": {
                      "install": {
                        "id": "connector-windows",
                        "section": null,
                        "title": "Install a connector on Windows",
                        "url": "https://cdapi.cloudraw.com/guides/connector-windows",
                        "pdf_url": "https://cdapi.cloudraw.com/guides/connector-windows.pdf"
                      },
                      "updates": {
                        "id": "connector-updates",
                        "section": null,
                        "title": "Connector updates",
                        "url": "https://cdapi.cloudraw.com/guides/connector-updates",
                        "pdf_url": "https://cdapi.cloudraw.com/guides/connector-updates.pdf"
                      },
                      "high_availability": {
                        "id": "connector-ha",
                        "section": null,
                        "title": "Connector high availability",
                        "url": "https://cdapi.cloudraw.com/guides/connector-ha",
                        "pdf_url": "https://cdapi.cloudraw.com/guides/connector-ha.pdf"
                      },
                      "remoteapp_helper": {
                        "id": "connector-remoteapp-helper",
                        "section": null,
                        "title": "RemoteApp helper",
                        "url": "https://cdapi.cloudraw.com/guides/connector-remoteapp-helper",
                        "pdf_url": "https://cdapi.cloudraw.com/guides/connector-remoteapp-helper.pdf"
                      }
                    },
                    "status": {
                      "phase": "pending",
                      "observed_at": null,
                      "message": "waiting for connector to come online"
                    },
                    "version": 1,
                    "created_by_integrator": null,
                    "claim_burned_at": null,
                    "bitlocker": null
                  },
                  "install_command": "powershell -NoProfile -ExecutionPolicy Bypass -Command \"[Net.ServicePointManager]::SecurityProtocol = 3072; irm 'https://cdapi.cloudraw.com/c/k3m9x0d2q8s1w7pa' | iex\"",
                  "claim_url": "https://cdapi.cloudraw.com/c/k3m9x0d2q8s1w7pa",
                  "claim_expires_at": "2026-10-14T09:24:11.000Z",
                  "claim_code": "k3m9x0d2q8s1w7pa",
                  "installer": {
                    "url": "https://cdapi.cloudraw.com/connector/staged/cloudraw-connector-setup-1.18.7-b11c.exe",
                    "file_name": "cloudraw-connector-setup-1.18.7-b11c.exe",
                    "sha256": "9f2c4e1a7b3d5f8e0a6c2b4d9e1f3a5c7b9d0e2f4a6c8b0d2e4f6a8c0b2d4e6f",
                    "signer": "Cloudraw Ltd",
                    "version": "1.18.7-b11c",
                    "silent_command": "cloudraw-connector-setup-1.18.7-b11c.exe /S /CODE=k3m9x0d2q8s1w7pa",
                    "silent_command_file": null
                  },
                  "install_steps": [
                    {
                      "title": "Install the Cloudraw Connector",
                      "command": "powershell -NoProfile -ExecutionPolicy Bypass -Command \"[Net.ServicePointManager]::SecurityProtocol = 3072; irm 'https://cdapi.cloudraw.com/c/k3m9x0d2q8s1w7pa' | iex\"",
                      "note": "Run in an Administrator PowerShell on any Windows machine in your network. Outbound-only. The short link enrolls this connector and expires soon — run it now.",
                      "verify": "connector_online"
                    }
                  ],
                  "setup_url": null,
                  "enrollment_jwt": "eyJhbGciOiJSUzI1NiIsImtpZCI6Ii4uLiJ9.eyJleHAiOjE3NjA5NTE0NTF9.c2lnbmF0dXJl",
                  "expires_at": "2026-10-19T15:02:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`connector-not-found`: No connector with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "connector-not-found": {
                    "summary": "No connector with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/connector-not-found",
                      "code": "connector-not-found",
                      "title": "connector not found",
                      "status": 404,
                      "detail": "No connector with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`already-installed`: The connector has already installed; nothing to reinstall.\n\n`idempotency-key-reuse`: The same `Idempotency-Key` was used with a different body within 24 hours.\n\n`already-issued`: This `Idempotency-Key` already created a secret; it is shown only once. Retry with a new key.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "already-installed": {
                    "summary": "The connector has already installed; nothing to reinstall.",
                    "value": {
                      "type": "https://cloudraw.com/problems/already-installed",
                      "code": "already-installed",
                      "title": "already installed",
                      "status": 409,
                      "detail": "The connector has already installed; nothing to reinstall."
                    }
                  },
                  "idempotency-key-reuse": {
                    "summary": "The same `Idempotency-Key` was used with a different body within 24 hours.",
                    "value": {
                      "type": "https://cloudraw.com/problems/idempotency-key-reuse",
                      "code": "idempotency-key-reuse",
                      "title": "idempotency key reuse",
                      "status": 409,
                      "detail": "The same Idempotency-Key was used with a different body within 24 hours."
                    }
                  },
                  "already-issued": {
                    "summary": "This `Idempotency-Key` already created a secret; it is shown only once. Retry with a new key.",
                    "value": {
                      "type": "https://cloudraw.com/problems/already-issued",
                      "code": "already-issued",
                      "title": "already issued",
                      "status": 409,
                      "detail": "This Idempotency-Key already created a secret; it is shown only once. Retry with a new key."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`lookup-failed`: Cloudraw could not read the connector identity; retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "lookup-failed": {
                    "summary": "Cloudraw could not read the connector identity; retry.",
                    "value": {
                      "type": "https://cloudraw.com/problems/lookup-failed",
                      "code": "lookup-failed",
                      "title": "lookup failed",
                      "status": 502,
                      "detail": "Cloudraw could not read the connector identity; retry."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        },
        "x-cloudraw-idempotent": "secret"
      }
    },
    "/v0/tenants/{tenant_id}/connectors/{connector_id}/trust": {
      "get": {
        "tags": [
          "Connectors"
        ],
        "operationId": "getConnectorTrust",
        "summary": "Get connector trust",
        "description": "Returns whether the connector is trusted to host, and why. An untrusted or pending connector is kept offline, so its apps are unreachable. Approving or blocking a connector is done in the Cloudraw console (it needs a second-factor check).\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "connector_id",
            "in": "path",
            "required": true,
            "description": "Connector id (from `GET …/connectors`).",
            "schema": {
              "type": "string"
            },
            "example": "cn0r4w8t2kq"
          }
        ],
        "responses": {
          "200": {
            "description": "Trust state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnectorTrustState"
                },
                "example": {
                  "connector_id": "cn0r4w8t2kq",
                  "state": "trusted",
                  "reason": "connector trusted",
                  "source": "default",
                  "evaluated_at": "2026-10-13T09:24:11.000Z",
                  "manual": null,
                  "approved": false
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`connector-not-found`: No connector with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "connector-not-found": {
                    "summary": "No connector with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/connector-not-found",
                      "code": "connector-not-found",
                      "title": "connector not found",
                      "status": 404,
                      "detail": "No connector with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/connectors/{connector_id}/update": {
      "post": {
        "tags": [
          "Connector updates"
        ],
        "operationId": "requestConnectorUpdate",
        "summary": "Update a connector now",
        "description": "Asks the connector to update now, regardless of the maintenance window. The connector applies it on its next check (every 15 minutes); follow `update.requested_at` / `applied_at` in `GET …/connectors`. A connector without an updater (`update.updater_state` `never_checked` or `none`) never picks it up: run `enable-updates` first. Audited.\n\n**Token:** full access · **Created by:** owner\n\n**Idempotency:** send `Idempotency-Key` to retry safely — the same key and body within 24 h returns the first answer.\n\n**Rate limit:** At most 10 connector commands (Update now, Turn on automatic updates, Pause, Resume) per 10 minutes per workspace, counted across every admin, integration and API token. A refused or failed command does not use up the budget.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "connector_id",
            "in": "path",
            "required": true,
            "description": "Connector id (from `GET …/connectors`).",
            "schema": {
              "type": "string"
            },
            "example": "cn0r4w8t2kq"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "version": {
                    "type": "string",
                    "description": "Target version (up to 20 characters). Default: the current release."
                  }
                }
              },
              "example": {}
            }
          }
        },
        "responses": {
          "202": {
            "description": "Requested.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnectorUpdateRequested"
                },
                "example": {
                  "connector_id": "cn0r4w8t2kq",
                  "requested_at": "2026-10-13T09:24:11.000Z",
                  "target_version": "1.18.7-b11c",
                  "note": "the connector applies it on its next check (every 15 minutes)"
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`connector-not-found`: No connector with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "connector-not-found": {
                    "summary": "No connector with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/connector-not-found",
                      "code": "connector-not-found",
                      "title": "connector not found",
                      "status": 404,
                      "detail": "No connector with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`updates-paused`: Automatic updates of this connector are paused. Resume them first.\n\n`version-frozen`: This release is on hold after a failed update elsewhere; the connector keeps its current version.\n\n`idempotency-key-reuse`: The same `Idempotency-Key` was used with a different body within 24 hours.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "updates-paused": {
                    "summary": "Automatic updates of this connector are paused. Resume them first.",
                    "value": {
                      "type": "https://cloudraw.com/problems/updates-paused",
                      "code": "updates-paused",
                      "title": "updates paused",
                      "status": 409,
                      "detail": "Automatic updates of this connector are paused. Resume them first."
                    }
                  },
                  "version-frozen": {
                    "summary": "This release is on hold after a failed update elsewhere; the connector keeps its current version.",
                    "value": {
                      "type": "https://cloudraw.com/problems/version-frozen",
                      "code": "version-frozen",
                      "title": "version frozen",
                      "status": 409,
                      "detail": "This release is on hold after a failed update elsewhere; the connector keeps its current version."
                    }
                  },
                  "idempotency-key-reuse": {
                    "summary": "The same `Idempotency-Key` was used with a different body within 24 hours.",
                    "value": {
                      "type": "https://cloudraw.com/problems/idempotency-key-reuse",
                      "code": "idempotency-key-reuse",
                      "title": "idempotency key reuse",
                      "status": 409,
                      "detail": "The same Idempotency-Key was used with a different body within 24 hours."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`too-many-connector-commands`: More than 10 connector commands in 10 minutes in this workspace. Wait `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "too-many-connector-commands": {
                    "summary": "More than 10 connector commands in 10 minutes in this workspace. Wait `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/too-many-connector-commands",
                      "code": "too-many-connector-commands",
                      "title": "too many connector commands",
                      "status": 429,
                      "detail": "More than 10 connector commands in 10 minutes in this workspace. Wait Retry-After seconds."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        },
        "x-cloudraw-rate-limit": "At most 10 connector commands (Update now, Turn on automatic updates, Pause, Resume) per 10 minutes per workspace, counted across every admin, integration and API token. A refused or failed command does not use up the budget.",
        "x-cloudraw-idempotent": true
      }
    },
    "/v0/tenants/{tenant_id}/connectors/{connector_id}/update-mode": {
      "get": {
        "tags": [
          "Connector updates"
        ],
        "operationId": "getConnectorUpdateMode",
        "summary": "Get a connector's update mode",
        "description": "The mode this connector follows, where it comes from, and the workspace connector default it would inherit.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "connector_id",
            "in": "path",
            "required": true,
            "description": "Connector id (from `GET …/connectors`).",
            "schema": {
              "type": "string"
            },
            "example": "cn0r4w8t2kq"
          }
        ],
        "responses": {
          "200": {
            "description": "The mode.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "connector_id": {
                      "type": "string"
                    },
                    "mode": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "mode_source": {
                      "type": "string",
                      "enum": [
                        "connector",
                        "workspace",
                        "paused"
                      ]
                    },
                    "mode_override": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "mode_override_by": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "mode_override_at": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "workspace_mode": {
                      "type": "string",
                      "enum": [
                        "auto_window",
                        "manual",
                        "immediate"
                      ]
                    }
                  },
                  "required": [
                    "connector_id",
                    "mode",
                    "mode_source"
                  ]
                },
                "example": {
                  "connector_id": "cn0r4w8t2kq",
                  "mode": "manual",
                  "mode_source": "connector",
                  "mode_override": "manual",
                  "mode_override_by": "dana.levi@example.com",
                  "mode_override_at": "2026-10-13T09:24:11.000Z",
                  "workspace_mode": "auto_window"
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`connector-not-found`: No connector with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "connector-not-found": {
                    "summary": "No connector with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/connector-not-found",
                      "code": "connector-not-found",
                      "title": "connector not found",
                      "status": 404,
                      "detail": "No connector with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      },
      "put": {
        "tags": [
          "Connector updates"
        ],
        "operationId": "setConnectorUpdateMode",
        "summary": "Set or clear a connector's update mode",
        "description": "Overrides the workspace connector default for this connector, or `inherit` (or null) to follow it again. A pause (`…/updates/pause`) still wins; this does not resume a paused connector. Repeating the current value changes nothing. Audited (`connector.update_mode.set`).\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "connector_id",
            "in": "path",
            "required": true,
            "description": "Connector id (from `GET …/connectors`).",
            "schema": {
              "type": "string"
            },
            "example": "cn0r4w8t2kq"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mode": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "enum": [
                      "inherit",
                      "immediate",
                      "auto_window",
                      "manual",
                      null
                    ]
                  }
                },
                "required": [
                  "mode"
                ]
              },
              "example": {
                "mode": "manual"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The connector's update state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnectorUpdateState"
                },
                "example": {
                  "connector_id": "cn0r4w8t2kq",
                  "update": {
                    "mode": "manual",
                    "mode_source": "connector",
                    "mode_override": "manual",
                    "mode_override_by": "dana.levi@example.com",
                    "mode_override_at": "2026-10-13T09:24:11.000Z",
                    "rollout": null,
                    "current_version": "1.18.7-b11c",
                    "build_known": true,
                    "available_version": null,
                    "previous_version": "1.18.7-b9c",
                    "requested_at": null,
                    "applied_at": "2026-10-11T02:14:09.000Z",
                    "last_check_at": "2026-10-13T09:15:02.000Z",
                    "last": {
                      "ok": true,
                      "from": "1.18.7-b9c",
                      "to": "1.18.7-b11c",
                      "message": "updated",
                      "at": "2026-10-11T02:14:09.000Z"
                    },
                    "updater": true,
                    "token_rotated_at": "2026-10-02T11:40:00.000Z",
                    "paused": null,
                    "last_paused": null,
                    "updater_state": "ok",
                    "last_reject_at": null
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid-request`: `mode` is not inherit, immediate, auto_window or manual (`paused` has its own route).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-request": {
                    "summary": "`mode` is not inherit, immediate, auto_window or manual (`paused` has its own route).",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-request",
                      "code": "invalid-request",
                      "title": "invalid request",
                      "status": 400,
                      "detail": "mode is not inherit, immediate, auto_window or manual (paused has its own route)."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`connector-not-found`: No connector with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "connector-not-found": {
                    "summary": "No connector with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/connector-not-found",
                      "code": "connector-not-found",
                      "title": "connector not found",
                      "status": 404,
                      "detail": "No connector with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/connectors/{connector_id}/updates/pause": {
      "post": {
        "tags": [
          "Connector updates"
        ],
        "operationId": "pauseConnectorUpdates",
        "summary": "Pause automatic updates",
        "description": "Stops all updates of this connector on purpose, with a reason every admin sees. A pending \"Update now\" is dropped, not applied later. The connector keeps running its current version until you resume. Audited.\n\n**Token:** full access · **Created by:** owner\n\n**Rate limit:** At most 10 connector commands (Update now, Turn on automatic updates, Pause, Resume) per 10 minutes per workspace, counted across every admin, integration and API token. A refused or failed command does not use up the budget.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "connector_id",
            "in": "path",
            "required": true,
            "description": "Connector id (from `GET …/connectors`).",
            "schema": {
              "type": "string"
            },
            "example": "cn0r4w8t2kq"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string",
                    "description": "Why, 3-300 characters. Shown to every admin.",
                    "minLength": 3,
                    "maxLength": 300
                  }
                },
                "required": [
                  "reason"
                ]
              },
              "example": {
                "reason": "Hold until the ERP upgrade on Friday is done"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnectorUpdateState"
                },
                "example": {
                  "connector_id": "cn0r4w8t2kq",
                  "update": {
                    "mode": "auto_window",
                    "mode_source": "workspace",
                    "mode_override": null,
                    "mode_override_by": null,
                    "mode_override_at": null,
                    "rollout": null,
                    "current_version": "1.18.7-b11c",
                    "build_known": true,
                    "available_version": null,
                    "previous_version": "1.18.7-b9c",
                    "requested_at": null,
                    "applied_at": "2026-10-11T02:14:09.000Z",
                    "last_check_at": "2026-10-13T09:15:02.000Z",
                    "last": {
                      "ok": true,
                      "from": "1.18.7-b9c",
                      "to": "1.18.7-b11c",
                      "message": "updated",
                      "at": "2026-10-11T02:14:09.000Z"
                    },
                    "updater": true,
                    "token_rotated_at": "2026-10-02T11:40:00.000Z",
                    "paused": {
                      "at": "2026-10-13T09:24:11.000Z",
                      "by": "dana.levi@example.com",
                      "reason": "Hold until the ERP upgrade on Friday is done"
                    },
                    "last_paused": null,
                    "updater_state": "paused",
                    "last_reject_at": null
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid-request`: `reason` is missing or not 3-300 characters.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-request": {
                    "summary": "`reason` is missing or not 3-300 characters.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-request",
                      "code": "invalid-request",
                      "title": "invalid request",
                      "status": 400,
                      "detail": "reason is missing or not 3-300 characters."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`connector-not-found`: No connector with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "connector-not-found": {
                    "summary": "No connector with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/connector-not-found",
                      "code": "connector-not-found",
                      "title": "connector not found",
                      "status": 404,
                      "detail": "No connector with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`too-many-connector-commands`: More than 10 connector commands in 10 minutes in this workspace. Wait `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "too-many-connector-commands": {
                    "summary": "More than 10 connector commands in 10 minutes in this workspace. Wait `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/too-many-connector-commands",
                      "code": "too-many-connector-commands",
                      "title": "too many connector commands",
                      "status": 429,
                      "detail": "More than 10 connector commands in 10 minutes in this workspace. Wait Retry-After seconds."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        },
        "x-cloudraw-rate-limit": "At most 10 connector commands (Update now, Turn on automatic updates, Pause, Resume) per 10 minutes per workspace, counted across every admin, integration and API token. A refused or failed command does not use up the budget."
      }
    },
    "/v0/tenants/{tenant_id}/connectors/{connector_id}/updates/resume": {
      "post": {
        "tags": [
          "Connector updates"
        ],
        "operationId": "resumeConnectorUpdates",
        "summary": "Resume automatic updates",
        "description": "Ends a pause: the connector follows the workspace update policy again. The pause is kept in `update.last_paused` for the record. Audited.\n\n**Token:** full access · **Created by:** owner\n\n**Rate limit:** At most 10 connector commands (Update now, Turn on automatic updates, Pause, Resume) per 10 minutes per workspace, counted across every admin, integration and API token. A refused or failed command does not use up the budget.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "connector_id",
            "in": "path",
            "required": true,
            "description": "Connector id (from `GET …/connectors`).",
            "schema": {
              "type": "string"
            },
            "example": "cn0r4w8t2kq"
          }
        ],
        "responses": {
          "200": {
            "description": "Resumed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnectorUpdateState"
                },
                "example": {
                  "connector_id": "cn0r4w8t2kq",
                  "update": {
                    "mode": "auto_window",
                    "mode_source": "workspace",
                    "mode_override": null,
                    "mode_override_by": null,
                    "mode_override_at": null,
                    "rollout": null,
                    "current_version": "1.18.7-b11c",
                    "build_known": true,
                    "available_version": null,
                    "previous_version": "1.18.7-b9c",
                    "requested_at": null,
                    "applied_at": "2026-10-11T02:14:09.000Z",
                    "last_check_at": "2026-10-13T09:15:02.000Z",
                    "last": {
                      "ok": true,
                      "from": "1.18.7-b9c",
                      "to": "1.18.7-b11c",
                      "message": "updated",
                      "at": "2026-10-11T02:14:09.000Z"
                    },
                    "updater": true,
                    "token_rotated_at": "2026-10-02T11:40:00.000Z",
                    "paused": null,
                    "last_paused": {
                      "at": "2026-10-09T08:00:00.000Z",
                      "by": "dana.levi@example.com",
                      "reason": "Hold until the ERP upgrade on Friday is done",
                      "resumed_at": "2026-10-13T09:24:11.000Z",
                      "resumed_by": "dana.levi@example.com"
                    },
                    "updater_state": "ok",
                    "last_reject_at": null
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`connector-not-found`: No connector with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "connector-not-found": {
                    "summary": "No connector with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/connector-not-found",
                      "code": "connector-not-found",
                      "title": "connector not found",
                      "status": 404,
                      "detail": "No connector with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`not-paused`: Automatic updates of this connector are not paused.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not-paused": {
                    "summary": "Automatic updates of this connector are not paused.",
                    "value": {
                      "type": "https://cloudraw.com/problems/not-paused",
                      "code": "not-paused",
                      "title": "not paused",
                      "status": 409,
                      "detail": "Automatic updates of this connector are not paused."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`too-many-connector-commands`: More than 10 connector commands in 10 minutes in this workspace. Wait `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "too-many-connector-commands": {
                    "summary": "More than 10 connector commands in 10 minutes in this workspace. Wait `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/too-many-connector-commands",
                      "code": "too-many-connector-commands",
                      "title": "too many connector commands",
                      "status": 429,
                      "detail": "More than 10 connector commands in 10 minutes in this workspace. Wait Retry-After seconds."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        },
        "x-cloudraw-rate-limit": "At most 10 connector commands (Update now, Turn on automatic updates, Pause, Resume) per 10 minutes per workspace, counted across every admin, integration and API token. A refused or failed command does not use up the budget."
      }
    },
    "/v0/tenants/{tenant_id}/customer-report": {
      "get": {
        "tags": [
          "Reports"
        ],
        "operationId": "getCustomerReport",
        "summary": "Get the monthly report",
        "description": "Builds the monthly access report for one calendar month (UTC): people, devices, connectors, published apps and networks, sessions, configuration changes and incidents. By default it answers a printable HTML page (A4); with `format=json` it answers only the headline numbers. The report is built on demand from current data and the month's audit log, so it is not cached and nothing is saved.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "month",
            "in": "query",
            "required": false,
            "description": "Month to report, `YYYY-MM` with a month from `01` to `12`. Missing: the current month (UTC). Any other value: `400 invalid-month`.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{4}-(0[1-9]|1[0-2])$"
            },
            "example": "2026-09"
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "`json` answers the summary as JSON; anything else (or omitted) answers the HTML report.",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "html"
              ]
            },
            "example": "json"
          }
        ],
        "responses": {
          "200": {
            "description": "With `format=json`: the summary. Otherwise: the full report as an HTML page (`text/html`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerReportSummary"
                },
                "example": {
                  "month": "2026-09",
                  "label": "September 2026",
                  "stats": {
                    "people": 18,
                    "devices": 21,
                    "sessions": 412,
                    "incidents": 2,
                    "changes": 6
                  }
                }
              },
              "text/html": {
                "schema": {
                  "type": "string",
                  "description": "A complete, self-contained HTML document."
                },
                "example": "<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\"><title>Northwind Logistics — Cloudraw access report, September 2026</title>…</head><body><h1>Northwind Logistics — September 2026</h1>…</body></html>"
              }
            }
          },
          "400": {
            "description": "`invalid-month`: `month` is not `YYYY-MM` with a month from 01 to 12 (for example `2026-13`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-month": {
                    "summary": "`month` is not `YYYY-MM` with a month from 01 to 12 (for example `2026-13`).",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-month",
                      "code": "invalid-month",
                      "title": "invalid month",
                      "status": 400,
                      "detail": "month is not YYYY-MM with a month from 01 to 12 (for example 2026-13)."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`report-failed`: The report could not be built; retry later.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "report-failed": {
                    "summary": "The report could not be built; retry later.",
                    "value": {
                      "type": "https://cloudraw.com/problems/report-failed",
                      "code": "report-failed",
                      "title": "report failed",
                      "status": 500,
                      "detail": "The report could not be built; retry later."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/devices": {
      "get": {
        "tags": [
          "Devices"
        ],
        "operationId": "listDevices",
        "summary": "List devices",
        "description": "Returns every device in the workspace with its owner, live status, trust decision, health and whether it can reach anything right now (`access` / `blocked_by`). Live status is read fresh on each call, so the answer can take a few seconds; when it cannot be read, `status_known` is false and the last known values are returned. Public IPs are always masked.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "responses": {
          "200": {
            "description": "All devices (not paginated).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceList"
                },
                "example": {
                  "items": [
                    {
                      "id": "dvc_5mxq2b7r8k",
                      "name": "dana-laptop",
                      "short_id": "2b7r8k",
                      "identity_id": "Xk3m9PqR2",
                      "os": "Windows 11 Pro",
                      "os_name": "Windows",
                      "os_version": "Windows 11 Pro",
                      "hostname": "NW-LT-0142",
                      "client_app": "Cloudraw Connect",
                      "public_ip_masked": "203.0.113.x",
                      "public_ip_version": 4,
                      "public_ip_at": "2026-10-13T09:15:02.000Z",
                      "public_ip_source": "device-api",
                      "hostname_shared": false,
                      "hostname_shared_with": [],
                      "person_id": "pz81kd03mna",
                      "person_name": "Dana Levi",
                      "created_by_integrator": null,
                      "online": true,
                      "status_known": true,
                      "last_seen": "2026-10-13T09:24:11.000Z",
                      "access": "allowed",
                      "blocked_by": null,
                      "quarantined": false,
                      "quarantined_at": null,
                      "quarantine_reason": null,
                      "trust": {
                        "state": "trusted",
                        "reason": "matched trust rule \"Managed laptops\"",
                        "unmet": [],
                        "evaluated_at": "2026-10-13T09:24:11.000Z",
                        "source": "rule",
                        "manual": null
                      },
                      "health": {
                        "state": "ok",
                        "summary": "Meets all 2 required checks",
                        "stale": false,
                        "requirements": [
                          {
                            "field": "disk_encrypted",
                            "label": "Disk encrypted",
                            "expected": true,
                            "met": true,
                            "text": null
                          },
                          {
                            "field": "firewall_on",
                            "label": "Firewall on",
                            "expected": true,
                            "met": true,
                            "text": null
                          }
                        ],
                        "recommendations": [],
                        "facts": [
                          {
                            "field": "domain_joined",
                            "label": "Joined to a domain",
                            "value": true
                          }
                        ],
                        "reported_at": "2026-10-13T09:15:02.000Z"
                      },
                      "posture": {
                        "compliant": true,
                        "checks": {
                          "disk_encrypted": true,
                          "antivirus_present": true,
                          "antivirus_on": true,
                          "firewall_on": true,
                          "os_up_to_date": true,
                          "screen_lock": true,
                          "domain_joined": true,
                          "workgroup": false,
                          "managed": true
                        },
                        "evaluated_at": "2026-10-13T09:15:02.000Z",
                        "source": "device",
                        "client_version": "0.4.7",
                        "freshness": "fresh",
                        "age_s": 549
                      },
                      "bitlocker": null,
                      "web_filter": null,
                      "app_firewall": {
                        "capable": true,
                        "client_version": "0.4.7"
                      },
                      "connect": {
                        "version": "0.4.7",
                        "latest": "0.4.7",
                        "update_available": false,
                        "reported": true
                      },
                      "connect_version": "0.4.7",
                      "connect_version_reported_at": "2026-10-13T08:40:02.000Z",
                      "inventory": {
                        "client_version": "1.2.4",
                        "hostname": "NW-LT-0142",
                        "os": "Windows",
                        "os_version": "Windows 11 Pro"
                      },
                      "remote_assist": {
                        "available": false,
                        "eligible": false,
                        "modes": [],
                        "reason": "not_available"
                      },
                      "state": "approved",
                      "created_at": "2026-09-20T07:41:00.000Z",
                      "enrolled_at": "2026-09-20T07:44:12.000Z",
                      "enrollment_used": true,
                      "created_via": "sign-in",
                      "enrolled_by": {
                        "kind": "person",
                        "id": "pz81kd03mna",
                        "label": "dana.levi@example.com"
                      },
                      "delivery": "sso",
                      "last_auth_at": "2026-10-13T06:58:40.000Z",
                      "last_resource_sync_at": "2026-10-13T09:20:00.000Z",
                      "sync_requested": false
                    }
                  ],
                  "next_page": null,
                  "connect_latest": "0.4.7"
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/devices/{device_id}": {
      "patch": {
        "tags": [
          "Devices"
        ],
        "operationId": "assignDevice",
        "summary": "Assign a device to a person",
        "description": "Sets (or clears, with `null`) the person a device belongs to. The device's group-based access follows immediately: rules granted to the person's groups apply on the next connection. Audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "device_id",
            "in": "path",
            "required": true,
            "description": "Device id (from `GET /devices`). A device keeps the id of the enrollment that created it.",
            "schema": {
              "type": "string"
            },
            "example": "dvc_5mxq2b7r8k"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "person_id": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Person id, or null to detach the device from its person."
                  }
                },
                "required": [
                  "person_id"
                ]
              },
              "example": {
                "person_id": "pz81kd03mna"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The new assignment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceOwnerChange"
                },
                "example": {
                  "id": "dvc_5mxq2b7r8k",
                  "device_name": "dana-laptop",
                  "person_id": "pz81kd03mna",
                  "person_name": "Dana Levi",
                  "previous_person_id": null
                }
              }
            }
          },
          "400": {
            "description": "`person-id-required`: The body has no `person_id` field (send null to detach).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "person-id-required": {
                    "summary": "The body has no `person_id` field (send null to detach).",
                    "value": {
                      "type": "https://cloudraw.com/problems/person-id-required",
                      "code": "person-id-required",
                      "title": "person id required",
                      "status": 400,
                      "detail": "The body has no person_id field (send null to detach)."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`device-not-found`: No device with this id in the workspace.\n\n`person-not-found`: `person_id` is not a person in this workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "device-not-found": {
                    "summary": "No device with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/device-not-found",
                      "code": "device-not-found",
                      "title": "device not found",
                      "status": 404,
                      "detail": "No device with this id in the workspace."
                    }
                  },
                  "person-not-found": {
                    "summary": "`person_id` is not a person in this workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/person-not-found",
                      "code": "person-not-found",
                      "title": "person not found",
                      "status": 404,
                      "detail": "person_id is not a person in this workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      },
      "delete": {
        "tags": [
          "Devices"
        ],
        "operationId": "deleteDevice",
        "summary": "Remove a device",
        "description": "Removes a device completely, e.g. a lost or retired laptop: its live connections are cut, its network identity is deleted (it can no longer connect), it is taken out of every access rule that names it, its just-in-time grants end and unused enrollment codes are revoked. A rule whose only device was this one then grants nobody (it never widens). Audited. If the identity cannot be deleted nothing is changed and you get `502`; retry.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "device_id",
            "in": "path",
            "required": true,
            "description": "Device id (from `GET /devices`). A device keeps the id of the enrollment that created it.",
            "schema": {
              "type": "string"
            },
            "example": "dvc_5mxq2b7r8k"
          }
        ],
        "responses": {
          "202": {
            "description": "Removed (`state` is `done`), with what was cleaned up.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceRemoval"
                },
                "example": {
                  "id": "task_8k2m0x9s",
                  "tenant_id": "tq7x2m9k4ab",
                  "state": "done",
                  "result_uri": null,
                  "error": null,
                  "removed": {
                    "identity": true,
                    "circuits_closed": 1,
                    "rules_updated": [
                      "pr_7xk2m9c0d1"
                    ],
                    "jit_grants_revoked": 0,
                    "enrolment_codes_revoked": 0
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`device-not-found`: No device with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "device-not-found": {
                    "summary": "No device with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/device-not-found",
                      "code": "device-not-found",
                      "title": "device not found",
                      "status": 404,
                      "detail": "No device with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`unenroll-failed`: The device could not be removed right now; nothing was changed. Retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unenroll-failed": {
                    "summary": "The device could not be removed right now; nothing was changed. Retry.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unenroll-failed",
                      "code": "unenroll-failed",
                      "title": "unenroll failed",
                      "status": 502,
                      "detail": "The device could not be removed right now; nothing was changed. Retry."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/devices/{device_id}/access-history": {
      "get": {
        "tags": [
          "Devices"
        ],
        "operationId": "getDeviceAccessHistory",
        "summary": "Get a device's access history",
        "description": "Which apps and private networks the device used, when and for how long, newest first, plus totals per app. Open sessions are included with `live: true`. History is kept 30 days; sessions shorter than about 30 seconds may be missing unless the connector reported them. The answer is sent with `Cache-Control: no-store`.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "device_id",
            "in": "path",
            "required": true,
            "description": "Device id (from `GET /devices`). A device keeps the id of the enrollment that created it.",
            "schema": {
              "type": "string"
            },
            "example": "dvc_5mxq2b7r8k"
          },
          {
            "name": "days",
            "in": "query",
            "required": false,
            "description": "Window in days (1-30).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 30,
              "default": 7
            },
            "example": 7
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum entries returned (1-1000). `by_app` always covers the whole window.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1000,
              "default": 200
            },
            "example": 200
          },
          {
            "name": "person_id",
            "in": "query",
            "required": false,
            "description": "Only sessions of this person.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "connection_id",
            "in": "query",
            "required": false,
            "description": "Only sessions to this app.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "description": "Only this kind of entry.",
            "schema": {
              "type": "string",
              "enum": [
                "device",
                "browser",
                "other"
              ]
            }
          },
          {
            "name": "include_probes",
            "in": "query",
            "required": false,
            "description": "true = also list the automatic Cloudraw Connect reachability checks, labelled `probe: true` (for exports); never in `by_app`.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The device's sessions.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceAccessHistory"
                },
                "example": {
                  "device_id": "dvc_5mxq2b7r8k",
                  "days": 7,
                  "items": [
                    {
                      "id": "ovl_4kx92m",
                      "kind": "device",
                      "device_id": "dvc_5mxq2b7r8k",
                      "device_name": "dana-laptop",
                      "person_id": "pz81kd03mna",
                      "user": "Dana Levi",
                      "app": "ERP",
                      "connection_id": "cx9m2v7d1pa",
                      "private_network_id": null,
                      "target": {
                        "type": "rdp",
                        "host": "10.20.0.15",
                        "port": 3389
                      },
                      "via": "cloudraw connect",
                      "started_at": "2026-10-13T07:02:10.000Z",
                      "ended_at": "2026-10-13T08:47:40.000Z",
                      "duration_s": 6330,
                      "live": false
                    }
                  ],
                  "by_app": [
                    {
                      "app": "ERP",
                      "sessions": 1,
                      "total_s": 6330
                    }
                  ],
                  "probes_excluded": 0,
                  "retention_days": 30,
                  "note": "Sessions shorter than about 30 seconds may be missing. The exact address inside a private network is coming with the connector update."
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`device-not-found`: No device with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "device-not-found": {
                    "summary": "No device with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/device-not-found",
                      "code": "device-not-found",
                      "title": "device not found",
                      "status": 404,
                      "detail": "No device with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/devices/{device_id}/quarantine": {
      "post": {
        "tags": [
          "Devices"
        ],
        "operationId": "quarantineDevice",
        "summary": "Quarantine a device",
        "description": "Cuts a device off at once: it is marked untrusted, its network identity is disabled (it cannot connect anywhere), every open session is ended and its just-in-time grants are revoked. Audited and raised as a security alert. Call with `?dry_run=true` first to see what it would cut (reachable resources and open sessions) without changing anything. Undo with `DELETE …/quarantine`.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "device_id",
            "in": "path",
            "required": true,
            "description": "Device id (from `GET /devices`). A device keeps the id of the enrollment that created it.",
            "schema": {
              "type": "string"
            },
            "example": "dvc_5mxq2b7r8k"
          },
          {
            "name": "dry_run",
            "in": "query",
            "required": false,
            "description": "`true` or `1`: only report the impact, change nothing.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "1"
              ]
            },
            "example": "true"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string",
                    "description": "Why (kept in the audit log and alert; cut at 300 characters)."
                  }
                }
              },
              "example": {
                "reason": "Laptop reported stolen"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The impact (dry run) or the result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceQuarantineResult"
                },
                "example": {
                  "dry_run": false,
                  "device_id": "dvc_5mxq2b7r8k",
                  "device": "dana-laptop",
                  "resources": [
                    {
                      "kind": "connection",
                      "id": "cx9m2v7d1pa",
                      "name": "ERP"
                    }
                  ],
                  "live_sessions": [
                    {
                      "id": "ovl_4kx92m",
                      "app": "erp",
                      "started_at": "2026-10-13T09:02:10.000Z"
                    }
                  ],
                  "overlay": "ok",
                  "already_quarantined": false,
                  "sessions_cut": 1,
                  "sessions_failed": 0,
                  "trust": {
                    "state": "untrusted",
                    "reason": "manually blocked by admin",
                    "unmet": [],
                    "evaluated_at": "2026-10-13T09:24:11.000Z",
                    "source": "manual",
                    "manual": "untrusted"
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`device-not-found`: No device with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "device-not-found": {
                    "summary": "No device with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/device-not-found",
                      "code": "device-not-found",
                      "title": "device not found",
                      "status": 404,
                      "detail": "No device with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`quarantine-failed`: The device could not be quarantined right now. Retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "quarantine-failed": {
                    "summary": "The device could not be quarantined right now. Retry.",
                    "value": {
                      "type": "https://cloudraw.com/problems/quarantine-failed",
                      "code": "quarantine-failed",
                      "title": "quarantine failed",
                      "status": 502,
                      "detail": "The device could not be quarantined right now. Retry."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      },
      "delete": {
        "tags": [
          "Devices"
        ],
        "operationId": "releaseDeviceQuarantine",
        "summary": "Release a device from quarantine",
        "description": "Re-enables the device's network identity and returns its trust to automatic (your trust rules decide again). Audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "device_id",
            "in": "path",
            "required": true,
            "description": "Device id (from `GET /devices`). A device keeps the id of the enrollment that created it.",
            "schema": {
              "type": "string"
            },
            "example": "dvc_5mxq2b7r8k"
          }
        ],
        "responses": {
          "200": {
            "description": "The device trust after release.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceTrust"
                },
                "example": {
                  "device_id": "dvc_5mxq2b7r8k",
                  "state": "trusted",
                  "reason": "matched trust rule \"Managed laptops\"",
                  "unmet": [],
                  "evaluated_at": "2026-10-13T09:24:11.000Z",
                  "source": "rule",
                  "manual": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`device-not-found`: No device with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "device-not-found": {
                    "summary": "No device with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/device-not-found",
                      "code": "device-not-found",
                      "title": "device not found",
                      "status": 404,
                      "detail": "No device with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`device-not-quarantined`: The device is not quarantined.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "device-not-quarantined": {
                    "summary": "The device is not quarantined.",
                    "value": {
                      "type": "https://cloudraw.com/problems/device-not-quarantined",
                      "code": "device-not-quarantined",
                      "title": "device not quarantined",
                      "status": 409,
                      "detail": "The device is not quarantined."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`release-failed`: The device could not be re-enabled right now; it stays quarantined. Retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "release-failed": {
                    "summary": "The device could not be re-enabled right now; it stays quarantined. Retry.",
                    "value": {
                      "type": "https://cloudraw.com/problems/release-failed",
                      "code": "release-failed",
                      "title": "release failed",
                      "status": 502,
                      "detail": "The device could not be re-enabled right now; it stays quarantined. Retry."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/devices/{device_id}/require-reauth": {
      "post": {
        "tags": [
          "Devices"
        ],
        "operationId": "requireDeviceReauth",
        "summary": "Require sign-in again on a device",
        "description": "Forces the person on this device to sign in again (suspected session theft, role change). Until they do, the device is untrusted and loses access that requires trust. Only for devices enrolled through sign-in. Audited.\n\n**Token:** full access · **Created by:** owner\n\n**Idempotency:** send `Idempotency-Key` to retry safely — the same key and body within 24 h returns the first answer.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "device_id",
            "in": "path",
            "required": true,
            "description": "Device id (from `GET /devices`). A device keeps the id of the enrollment that created it.",
            "schema": {
              "type": "string"
            },
            "example": "dvc_5mxq2b7r8k"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Re-authentication is now required.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "device_id": {
                      "type": "string"
                    },
                    "reauth_required": {
                      "type": "boolean"
                    },
                    "trust": {
                      "type": "object",
                      "properties": {
                        "state": {
                          "type": "string",
                          "enum": [
                            "trusted",
                            "untrusted"
                          ],
                          "description": "Trust decision right now."
                        },
                        "reason": {
                          "type": "string",
                          "description": "Plain-English reason for the decision."
                        },
                        "unmet": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/DeviceTrustUnmet"
                          },
                          "description": "What keeps the device from being trusted (empty when trusted or when no rule applies)."
                        },
                        "evaluated_at": {
                          "type": "string",
                          "format": "date-time",
                          "description": "When this decision was computed (now)."
                        },
                        "source": {
                          "type": "string",
                          "enum": [
                            "default",
                            "manual",
                            "rule",
                            "policy"
                          ],
                          "description": "`default` = the workspace has no trust rules yet; `manual` = set by an admin; `rule` = your trust rules; `policy` = a workspace policy (sign-in required, person suspended)."
                        }
                      }
                    }
                  },
                  "required": [
                    "device_id",
                    "reauth_required"
                  ]
                },
                "example": {
                  "device_id": "dvc_5mxq2b7r8k",
                  "reauth_required": true,
                  "trust": {
                    "state": "untrusted",
                    "reason": "sign-in required by your administrator — sign in again to continue",
                    "unmet": [
                      {
                        "kind": "reauth",
                        "field": "last_auth_at",
                        "op": "required",
                        "value": null,
                        "got": "2026-10-13T06:58:40.000Z",
                        "text": "Sign in again to continue"
                      }
                    ],
                    "evaluated_at": "2026-10-13T09:24:11.000Z",
                    "source": "policy"
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`device-not-found`: No device with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "device-not-found": {
                    "summary": "No device with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/device-not-found",
                      "code": "device-not-found",
                      "title": "device not found",
                      "status": 404,
                      "detail": "No device with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`not-a-signed-in-device`: The device was enrolled with a code, not through sign-in, so it cannot re-authenticate.\n\n`idempotency-key-reuse`: The same `Idempotency-Key` was used with a different body within 24 hours.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not-a-signed-in-device": {
                    "summary": "The device was enrolled with a code, not through sign-in, so it cannot re-authenticate.",
                    "value": {
                      "type": "https://cloudraw.com/problems/not-a-signed-in-device",
                      "code": "not-a-signed-in-device",
                      "title": "not a signed in device",
                      "status": 409,
                      "detail": "The device was enrolled with a code, not through sign-in, so it cannot re-authenticate."
                    }
                  },
                  "idempotency-key-reuse": {
                    "summary": "The same `Idempotency-Key` was used with a different body within 24 hours.",
                    "value": {
                      "type": "https://cloudraw.com/problems/idempotency-key-reuse",
                      "code": "idempotency-key-reuse",
                      "title": "idempotency key reuse",
                      "status": 409,
                      "detail": "The same Idempotency-Key was used with a different body within 24 hours."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        },
        "x-cloudraw-idempotent": true
      }
    },
    "/v0/tenants/{tenant_id}/devices/{device_id}/trust": {
      "get": {
        "tags": [
          "Devices"
        ],
        "operationId": "getDeviceTrust",
        "summary": "Get a device's trust",
        "description": "The trust decision for one device right now, why, what it is missing (`unmet`) and any manual override.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "device_id",
            "in": "path",
            "required": true,
            "description": "Device id (from `GET /devices`). A device keeps the id of the enrollment that created it.",
            "schema": {
              "type": "string"
            },
            "example": "dvc_5mxq2b7r8k"
          }
        ],
        "responses": {
          "200": {
            "description": "The trust decision.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceTrust"
                },
                "example": {
                  "device_id": "dvc_5mxq2b7r8k",
                  "state": "trusted",
                  "reason": "matched trust rule \"Managed laptops\"",
                  "unmet": [],
                  "evaluated_at": "2026-10-13T09:24:11.000Z",
                  "source": "rule",
                  "manual": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`device-not-found`: No device with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "device-not-found": {
                    "summary": "No device with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/device-not-found",
                      "code": "device-not-found",
                      "title": "device not found",
                      "status": 404,
                      "detail": "No device with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      },
      "post": {
        "tags": [
          "Devices"
        ],
        "operationId": "setDeviceTrust",
        "summary": "Override a device's trust",
        "description": "Sets a manual trust override: `trusted`, `untrusted`, or `auto` to remove the override and let your trust rules decide. When the device ends up blocked, its open sessions are ended and its just-in-time grants revoked right away. Audited. A quarantined device must be released first.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "device_id",
            "in": "path",
            "required": true,
            "description": "Device id (from `GET /devices`). A device keeps the id of the enrollment that created it.",
            "schema": {
              "type": "string"
            },
            "example": "dvc_5mxq2b7r8k"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "state": {
                    "type": "string",
                    "enum": [
                      "trusted",
                      "untrusted",
                      "auto"
                    ]
                  }
                },
                "required": [
                  "state"
                ]
              },
              "example": {
                "state": "untrusted"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The trust decision after the change.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/DeviceTrust"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "access_blocked": {
                          "type": "boolean",
                          "description": "The device is now cut off from every grant."
                        },
                        "sessions_cut": {
                          "type": "integer",
                          "description": "Open sessions ended by this call."
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "device_id": "dvc_5mxq2b7r8k",
                  "state": "untrusted",
                  "reason": "manually blocked by admin",
                  "unmet": [],
                  "evaluated_at": "2026-10-13T09:24:11.000Z",
                  "source": "manual",
                  "manual": "untrusted",
                  "access_blocked": true,
                  "sessions_cut": 1
                }
              }
            }
          },
          "400": {
            "description": "`invalid-state`: `state` is not `trusted`, `untrusted` or `auto`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-state": {
                    "summary": "`state` is not `trusted`, `untrusted` or `auto`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-state",
                      "code": "invalid-state",
                      "title": "invalid state",
                      "status": 400,
                      "detail": "state is not trusted, untrusted or auto."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`device-not-found`: No device with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "device-not-found": {
                    "summary": "No device with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/device-not-found",
                      "code": "device-not-found",
                      "title": "device not found",
                      "status": 404,
                      "detail": "No device with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`device-quarantined`: The device is quarantined; release it from quarantine first.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "device-quarantined": {
                    "summary": "The device is quarantined; release it from quarantine first.",
                    "value": {
                      "type": "https://cloudraw.com/problems/device-quarantined",
                      "code": "device-quarantined",
                      "title": "device quarantined",
                      "status": 409,
                      "detail": "The device is quarantined; release it from quarantine first."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/enrollments": {
      "get": {
        "tags": [
          "Enrollments"
        ],
        "operationId": "listEnrollments",
        "summary": "List pending enrollments",
        "description": "Device enrollments that were issued but not used yet and have not expired (\"waiting to enroll\"). Never returns a token or code. A device that has joined disappears from this list and shows in `GET /devices`.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "description": "Only `device` is supported.",
            "schema": {
              "type": "string",
              "enum": [
                "device"
              ]
            },
            "example": "device"
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "description": "Only `issued` is supported.",
            "schema": {
              "type": "string",
              "enum": [
                "issued"
              ]
            },
            "example": "issued"
          }
        ],
        "responses": {
          "200": {
            "description": "Pending enrollments (not paginated).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrollmentList"
                },
                "example": {
                  "items": [
                    {
                      "id": "en_7k2x9m0s1d",
                      "kind": "device",
                      "state": "issued",
                      "device_name": "omer-laptop",
                      "created_at": "2026-10-13T08:00:00.000Z",
                      "created_by_integrator": null,
                      "expires_at": "2026-10-20T08:00:00.000Z",
                      "claim_expires_at": "2026-10-13T09:00:00.000Z"
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "description": "`invalid-kind`: `kind` is not `device`.\n\n`invalid-state`: `state` is not `issued`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-kind": {
                    "summary": "`kind` is not `device`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-kind",
                      "code": "invalid-kind",
                      "title": "invalid kind",
                      "status": 400,
                      "detail": "kind is not device."
                    }
                  },
                  "invalid-state": {
                    "summary": "`state` is not `issued`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-state",
                      "code": "invalid-state",
                      "title": "invalid state",
                      "status": 400,
                      "detail": "state is not issued."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      },
      "post": {
        "tags": [
          "Enrollments"
        ],
        "operationId": "createEnrollment",
        "summary": "Create a device enrollment",
        "description": "Issues a one-time enrollment for a new device and returns how to join it: a short code (`claim_code`, valid 1 hour, entered in Cloudraw Connect), a link with the same code (`claim_url`) and the enrollment token itself (`jwt`, valid 7 days). Give one of them to the user over a direct channel. Counts toward the device quota. Audited.\n\n**Token:** full access · **Created by:** owner\n\n**Idempotency:** send `Idempotency-Key`. The answer carries a secret shown once: a retry with the same key answers `409 already-issued` instead of the secret.\n\n**Secret answer:** the token and code are shown only in this answer. Lost them? Cancel the enrollment (`DELETE /enrollments/{enrollment_id}`) and create a new one.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "device"
                    ],
                    "description": "Default `device`."
                  },
                  "delivery": {
                    "type": "string",
                    "enum": [
                      "token",
                      "code",
                      "qr",
                      "email"
                    ],
                    "description": "How you will hand the enrollment to the user (recorded on the device as `delivery`; the answer is the same). Default `token`. `sso` and `provision` are set by Cloudraw only."
                  },
                  "device_name": {
                    "type": "string",
                    "description": "Name for the device. Lowercased, other characters become `-`, at most 40 characters. Default `device-<n>`. Must not be in use by another device."
                  },
                  "person_id": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Person the device will belong to. An unknown id is ignored (the device is unassigned)."
                  }
                }
              },
              "example": {
                "device_name": "omer-laptop",
                "person_id": "p4hd8s0qk2l"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The enrollment, with its secrets. **Shown once**: they are never returned again and are not kept for Idempotency-Key replays. Sent with `Cache-Control: no-store`; do not cache or log it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrollmentCreated"
                },
                "example": {
                  "id": "en_7k2x9m0s1d",
                  "kind": "device",
                  "state": "issued",
                  "jwt": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJleGFtcGxlIn0.c2lnbmF0dXJl",
                  "claim_code": "CRW-7KQ2M-X9D4P",
                  "claim_url": "https://connect.example.com/d/CRW-7KQ2M-X9D4P",
                  "claim_expires_at": "2026-10-13T10:24:11.000Z",
                  "qr_png_base64": null,
                  "expires_at": "2026-10-20T09:24:11.000Z"
                }
              }
            }
          },
          "400": {
            "description": "`invalid-delivery`: `delivery` is not one of `token`, `code`, `qr`, `email`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-delivery": {
                    "summary": "`delivery` is not one of `token`, `code`, `qr`, `email`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-delivery",
                      "code": "invalid-delivery",
                      "title": "invalid delivery",
                      "status": 400,
                      "detail": "delivery is not one of token, code, qr, email."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`device-quota-reached`: The workspace already has as many devices as its plan allows.\n\n`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "device-quota-reached": {
                    "summary": "The workspace already has as many devices as its plan allows.",
                    "value": {
                      "type": "https://cloudraw.com/problems/device-quota-reached",
                      "code": "device-quota-reached",
                      "title": "device quota reached",
                      "status": 403,
                      "detail": "The workspace already has as many devices as its plan allows."
                    }
                  },
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`idempotency-key-reuse`: The same `Idempotency-Key` was used with a different body within 24 hours.\n\n`already-issued`: This `Idempotency-Key` already created a secret; it is shown only once. Retry with a new key.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "idempotency-key-reuse": {
                    "summary": "The same `Idempotency-Key` was used with a different body within 24 hours.",
                    "value": {
                      "type": "https://cloudraw.com/problems/idempotency-key-reuse",
                      "code": "idempotency-key-reuse",
                      "title": "idempotency key reuse",
                      "status": 409,
                      "detail": "The same Idempotency-Key was used with a different body within 24 hours."
                    }
                  },
                  "already-issued": {
                    "summary": "This `Idempotency-Key` already created a secret; it is shown only once. Retry with a new key.",
                    "value": {
                      "type": "https://cloudraw.com/problems/already-issued",
                      "code": "already-issued",
                      "title": "already issued",
                      "status": 409,
                      "detail": "This Idempotency-Key already created a secret; it is shown only once. Retry with a new key."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`provisioning-failed`: The device identity could not be created (for example the name is already in use, or a temporary failure). Nothing was issued; retry or choose another name.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "provisioning-failed": {
                    "summary": "The device identity could not be created (for example the name is already in use, or a temporary failure). Nothing was issued; retry or choose another name.",
                    "value": {
                      "type": "https://cloudraw.com/problems/provisioning-failed",
                      "code": "provisioning-failed",
                      "title": "provisioning failed",
                      "status": 502,
                      "detail": "The device identity could not be created (for example the name is already in use, or a temporary failure). Nothing was issued; retry or choose another name."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        },
        "x-cloudraw-idempotent": "secret"
      }
    },
    "/v0/tenants/{tenant_id}/enrollments/{enrollment_id}": {
      "get": {
        "tags": [
          "Enrollments"
        ],
        "operationId": "getEnrollment",
        "summary": "Get an enrollment",
        "description": "Metadata of one device enrollment: name, token expiry and whether a short code is live (`claim_expires_at`). Never returns a code or token (`claim_code` and `claim_url` are always null). Sent with `Cache-Control: no-store`.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "enrollment_id",
            "in": "path",
            "required": true,
            "description": "Enrollment id (from `POST /enrollments` or `GET /enrollments`).",
            "schema": {
              "type": "string"
            },
            "example": "en_7k2x9m0s1d"
          }
        ],
        "responses": {
          "200": {
            "description": "The enrollment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrollmentDetail"
                },
                "example": {
                  "id": "en_7k2x9m0s1d",
                  "device_name": "omer-laptop",
                  "claim_code": null,
                  "claim_url": null,
                  "claim_expires_at": "2026-10-13T09:00:00.000Z",
                  "expires_at": "2026-10-20T08:00:00.000Z",
                  "reveal_with": {
                    "method": "POST",
                    "path": "/v0/tenants/tq7x2m9k4ab/enrollments/en_7k2x9m0s1d"
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`enrollment-not-found`: No device enrollment with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "enrollment-not-found": {
                    "summary": "No device enrollment with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/enrollment-not-found",
                      "code": "enrollment-not-found",
                      "title": "enrollment not found",
                      "status": 404,
                      "detail": "No device enrollment with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      },
      "delete": {
        "tags": [
          "Enrollments"
        ],
        "operationId": "cancelEnrollment",
        "summary": "Cancel a pending enrollment",
        "description": "Cancels an enrollment that has not been used: its token can no longer be exchanged and every short code for it stops working. Audited. An enrollment that was already used is a device: remove it with `DELETE /devices/{device_id}`.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "enrollment_id",
            "in": "path",
            "required": true,
            "description": "Enrollment id (from `POST /enrollments` or `GET /enrollments`).",
            "schema": {
              "type": "string"
            },
            "example": "en_7k2x9m0s1d"
          }
        ],
        "responses": {
          "204": {
            "description": "Cancelled."
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`enrollment-not-found`: No pending device enrollment with this id.\n\n`enrollment-consumed`: The enrollment was already used; remove the device instead.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "enrollment-not-found": {
                    "summary": "No pending device enrollment with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/enrollment-not-found",
                      "code": "enrollment-not-found",
                      "title": "enrollment not found",
                      "status": 404,
                      "detail": "No pending device enrollment with this id."
                    }
                  },
                  "enrollment-consumed": {
                    "summary": "The enrollment was already used; remove the device instead.",
                    "value": {
                      "type": "https://cloudraw.com/problems/enrollment-consumed",
                      "code": "enrollment-consumed",
                      "title": "enrollment consumed",
                      "status": 404,
                      "detail": "The enrollment was already used; remove the device instead."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`cancel-failed`: The enrollment could not be cancelled right now; nothing was changed. Retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "cancel-failed": {
                    "summary": "The enrollment could not be cancelled right now; nothing was changed. Retry.",
                    "value": {
                      "type": "https://cloudraw.com/problems/cancel-failed",
                      "code": "cancel-failed",
                      "title": "cancel failed",
                      "status": 502,
                      "detail": "The enrollment could not be cancelled right now; nothing was changed. Retry."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/explain-access": {
      "get": {
        "tags": [
          "Access rules"
        ],
        "operationId": "explainAccess",
        "summary": "Explain access for a device",
        "description": "Answers \"why can (or can't) this device reach this app?\" without changing anything. It walks both gates in order — **trust** (is the device trusted, and is that required?) then **access** (does an enforced allow rule grant this device, its person or one of their groups?) — and explains each in plain English, including the device checks a rule needs that the device fails. Pass `device` plus either `connection` or `private_network`.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "device",
            "in": "query",
            "required": true,
            "description": "Device id.",
            "schema": {
              "type": "string"
            },
            "example": "dvc_5mxq2b7r8k"
          },
          {
            "name": "connection",
            "in": "query",
            "required": false,
            "description": "App id to check. Use this or `private_network`.",
            "schema": {
              "type": "string"
            },
            "example": "cx9m2v7d1pa"
          },
          {
            "name": "private_network",
            "in": "query",
            "required": false,
            "description": "Private network id to check instead of an app.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The verdict per gate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccessExplanation"
                },
                "example": {
                  "device": "dvc_5mxq2b7r8k",
                  "device_name": "FIN-LT-014",
                  "person": "Dana Levi",
                  "groups": [
                    "g3k9d0s7aa"
                  ],
                  "connection": "cx9m2v7d1pa",
                  "resource_kind": "connection",
                  "resource_name": "erp-db",
                  "verdict": "BLOCKED",
                  "reachable": false,
                  "blocked_at": "access",
                  "gates": [
                    {
                      "gate": "trust",
                      "label": "Trust (admission)",
                      "pass": true,
                      "detail": "Device is trusted → admitted to the overlay.",
                      "trust": {
                        "state": "trusted",
                        "reason": "matched trust rule \"Company laptops\"",
                        "unmet": [],
                        "evaluated_at": "2026-10-13T09:24:11.000Z",
                        "source": "rule",
                        "matched_rule": "tr_4m8s2k0x9q"
                      },
                      "admission_enforced": true
                    },
                    {
                      "gate": "access",
                      "label": "Access (authorization)",
                      "pass": false,
                      "detail": "Rule \"Finance → ERP from encrypted laptops\" applies to this device, but it fails required device checks: Disk encryption (BitLocker) is off.",
                      "matched_rule": null,
                      "considered": [
                        {
                          "rule": "pr_7xk2m9c0d1",
                          "name": "Finance → ERP from encrypted laptops",
                          "enforced": true,
                          "enforcement_reason": null,
                          "grants": false,
                          "missing_posture": [
                            "disk_encrypted"
                          ]
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "`valid-device-query-param-required`: `device` is missing or is not a device in this workspace.\n\n`valid-connection-query-param-required`: Neither a known `connection` nor `private_network` was given.\n\n`valid-private-network-query-param-required`: `private_network` is not a private network in this workspace.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "valid-device-query-param-required": {
                    "summary": "`device` is missing or is not a device in this workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/valid-device-query-param-required",
                      "code": "valid-device-query-param-required",
                      "title": "valid device query param required",
                      "status": 400,
                      "detail": "device is missing or is not a device in this workspace."
                    }
                  },
                  "valid-connection-query-param-required": {
                    "summary": "Neither a known `connection` nor `private_network` was given.",
                    "value": {
                      "type": "https://cloudraw.com/problems/valid-connection-query-param-required",
                      "code": "valid-connection-query-param-required",
                      "title": "valid connection query param required",
                      "status": 400,
                      "detail": "Neither a known connection nor private_network was given."
                    }
                  },
                  "valid-private-network-query-param-required": {
                    "summary": "`private_network` is not a private network in this workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/valid-private-network-query-param-required",
                      "code": "valid-private-network-query-param-required",
                      "title": "valid private network query param required",
                      "status": 400,
                      "detail": "private_network is not a private network in this workspace."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/fleet-compliance": {
      "get": {
        "tags": [
          "Devices"
        ],
        "operationId": "getFleetCompliance",
        "summary": "Get fleet compliance",
        "description": "How many devices meet the health checks your own trust and access rules require. Devices that never reported are not counted in `evaluated`; a device whose last report is too old counts as not compliant.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "responses": {
          "200": {
            "description": "The roll-up.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FleetCompliance"
                },
                "example": {
                  "total_devices": 23,
                  "evaluated": 21,
                  "compliant": 18,
                  "stale": 1,
                  "percent": 86,
                  "basis": "workspace-rules"
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/groups": {
      "get": {
        "tags": [
          "Groups"
        ],
        "operationId": "listGroups",
        "summary": "List groups",
        "description": "Returns every group in the workspace — created in Cloudraw, imported from Active Directory, or synced by your directory — with its members and how many rules use it. Not paginated; sorted by name.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "responses": {
          "200": {
            "description": "All groups.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupList"
                },
                "example": {
                  "items": [
                    {
                      "id": "g3k9d0s7aa",
                      "display_name": "Finance",
                      "source": "local",
                      "member_count": 2,
                      "members": [
                        {
                          "id": "pz81kd03mna",
                          "name": "Dana Levi",
                          "email": "dana.levi@example.com"
                        },
                        {
                          "id": "p4hd8s0qk2l",
                          "name": "Omer Katz",
                          "email": "omer.katz@example.com"
                        }
                      ],
                      "created_at": "2026-09-21T10:00:00.000Z",
                      "updated_at": "2026-10-13T09:24:11.000Z",
                      "used_by_rules": 2
                    }
                  ],
                  "directory_source": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      },
      "post": {
        "tags": [
          "Groups"
        ],
        "operationId": "createGroup",
        "summary": "Create a group",
        "description": "Creates a group managed in Cloudraw (`source: local`), optionally with members. Members' devices get the group's access at once. Use the group in access rules to grant it apps or networks. Audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Name, 1-80 characters, no control characters or `< >`. Unique in the workspace (case-insensitive). `display_name` is accepted as an alias."
                  },
                  "members": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Person ids (up to 500); each must exist."
                  }
                },
                "required": [
                  "name"
                ]
              },
              "example": {
                "name": "Finance",
                "members": [
                  "pz81kd03mna",
                  "p4hd8s0qk2l"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new group.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Group"
                },
                "example": {
                  "id": "g3k9d0s7aa",
                  "display_name": "Finance",
                  "source": "local",
                  "member_count": 2,
                  "members": [
                    {
                      "id": "pz81kd03mna",
                      "name": "Dana Levi",
                      "email": "dana.levi@example.com"
                    },
                    {
                      "id": "p4hd8s0qk2l",
                      "name": "Omer Katz",
                      "email": "omer.katz@example.com"
                    }
                  ],
                  "created_at": "2026-09-21T10:00:00.000Z",
                  "updated_at": "2026-09-21T10:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "`invalid-name`: The name is missing, longer than 80 characters or contains a forbidden character.\n\n`unknown-people`: Some `members` are not people in this workspace.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-name": {
                    "summary": "The name is missing, longer than 80 characters or contains a forbidden character.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-name",
                      "code": "invalid-name",
                      "title": "invalid name",
                      "status": 400,
                      "detail": "The name is missing, longer than 80 characters or contains a forbidden character."
                    }
                  },
                  "unknown-people": {
                    "summary": "Some `members` are not people in this workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unknown-people",
                      "code": "unknown-people",
                      "title": "unknown people",
                      "status": 400,
                      "detail": "Some members are not people in this workspace."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`group-exists`: A group with this name already exists.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "group-exists": {
                    "summary": "A group with this name already exists.",
                    "value": {
                      "type": "https://cloudraw.com/problems/group-exists",
                      "code": "group-exists",
                      "title": "group exists",
                      "status": 409,
                      "detail": "A group with this name already exists."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/groups/{group_id}": {
      "get": {
        "tags": [
          "Groups"
        ],
        "operationId": "getGroup",
        "summary": "Get a group",
        "description": "Returns one group with its members and the access and trust rules that use it.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "group_id",
            "in": "path",
            "required": true,
            "description": "Group id (from List groups).",
            "schema": {
              "type": "string"
            },
            "example": "g3k9d0s7aa"
          }
        ],
        "responses": {
          "200": {
            "description": "The group.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupDetail"
                },
                "example": {
                  "id": "g3k9d0s7aa",
                  "display_name": "Finance",
                  "source": "local",
                  "member_count": 2,
                  "members": [
                    {
                      "id": "pz81kd03mna",
                      "name": "Dana Levi",
                      "email": "dana.levi@example.com"
                    },
                    {
                      "id": "p4hd8s0qk2l",
                      "name": "Omer Katz",
                      "email": "omer.katz@example.com"
                    }
                  ],
                  "created_at": "2026-09-21T10:00:00.000Z",
                  "updated_at": "2026-10-13T09:24:11.000Z",
                  "used_by_rules": [
                    {
                      "id": "pr_7xk2m9c0d1",
                      "name": "Finance to ERP"
                    },
                    {
                      "id": "tr_4m8s2k0x9q",
                      "name": "Finance laptops",
                      "kind": "trust"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`group-not-found`: No group with this id (or it was deleted).\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "group-not-found": {
                    "summary": "No group with this id (or it was deleted).",
                    "value": {
                      "type": "https://cloudraw.com/problems/group-not-found",
                      "code": "group-not-found",
                      "title": "group not found",
                      "status": 404,
                      "detail": "No group with this id (or it was deleted)."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      },
      "patch": {
        "tags": [
          "Groups"
        ],
        "operationId": "updateGroup",
        "summary": "Update a group",
        "description": "Renames a group and/or adds and removes members. Only groups created in Cloudraw (`source: local`) can be changed; directory groups are changed in your directory. Members' device access is recalculated at once. Ids in `remove` that are not members are ignored. Audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "group_id",
            "in": "path",
            "required": true,
            "description": "Group id (from List groups).",
            "schema": {
              "type": "string"
            },
            "example": "g3k9d0s7aa"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "New name (same rules as on create). `display_name` is accepted as an alias."
                  },
                  "add": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Person ids to add (up to 500); each must exist."
                  },
                  "remove": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Person ids to remove (up to 500)."
                  }
                }
              },
              "example": {
                "add": [
                  "p4hd8s0qk2l"
                ],
                "remove": []
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated group.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Group"
                },
                "example": {
                  "id": "g3k9d0s7aa",
                  "display_name": "Finance",
                  "source": "local",
                  "member_count": 2,
                  "members": [
                    {
                      "id": "pz81kd03mna",
                      "name": "Dana Levi",
                      "email": "dana.levi@example.com"
                    },
                    {
                      "id": "p4hd8s0qk2l",
                      "name": "Omer Katz",
                      "email": "omer.katz@example.com"
                    }
                  ],
                  "created_at": "2026-09-21T10:00:00.000Z",
                  "updated_at": "2026-10-13T09:24:11.000Z"
                }
              }
            }
          },
          "400": {
            "description": "`invalid-name`: The new name is empty, longer than 80 characters or contains a forbidden character.\n\n`unknown-people`: Some ids in `add` are not people in this workspace.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-name": {
                    "summary": "The new name is empty, longer than 80 characters or contains a forbidden character.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-name",
                      "code": "invalid-name",
                      "title": "invalid name",
                      "status": 400,
                      "detail": "The new name is empty, longer than 80 characters or contains a forbidden character."
                    }
                  },
                  "unknown-people": {
                    "summary": "Some ids in `add` are not people in this workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unknown-people",
                      "code": "unknown-people",
                      "title": "unknown people",
                      "status": 400,
                      "detail": "Some ids in add are not people in this workspace."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`group-not-found`: No group with this id (or it was deleted).\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "group-not-found": {
                    "summary": "No group with this id (or it was deleted).",
                    "value": {
                      "type": "https://cloudraw.com/problems/group-not-found",
                      "code": "group-not-found",
                      "title": "group not found",
                      "status": 404,
                      "detail": "No group with this id (or it was deleted)."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`group-managed-elsewhere`: The group comes from your directory; change it there.\n\n`group-exists`: Another group already has this name.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "group-managed-elsewhere": {
                    "summary": "The group comes from your directory; change it there.",
                    "value": {
                      "type": "https://cloudraw.com/problems/group-managed-elsewhere",
                      "code": "group-managed-elsewhere",
                      "title": "group managed elsewhere",
                      "status": 409,
                      "detail": "The group comes from your directory; change it there."
                    }
                  },
                  "group-exists": {
                    "summary": "Another group already has this name.",
                    "value": {
                      "type": "https://cloudraw.com/problems/group-exists",
                      "code": "group-exists",
                      "title": "group exists",
                      "status": 409,
                      "detail": "Another group already has this name."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      },
      "delete": {
        "tags": [
          "Groups"
        ],
        "operationId": "deleteGroup",
        "summary": "Delete a group",
        "description": "Deletes a group created in Cloudraw, or un-imports an Active Directory group (the group in Active Directory is not touched). Its members lose the access it gave. Refused while any access or trust rule still uses the group: remove it from those rules first. Groups synced by SCIM or another directory are removed there. Audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "group_id",
            "in": "path",
            "required": true,
            "description": "Group id (from List groups).",
            "schema": {
              "type": "string"
            },
            "example": "g3k9d0s7aa"
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`group-not-found`: No group with this id (or it was deleted).\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "group-not-found": {
                    "summary": "No group with this id (or it was deleted).",
                    "value": {
                      "type": "https://cloudraw.com/problems/group-not-found",
                      "code": "group-not-found",
                      "title": "group not found",
                      "status": 404,
                      "detail": "No group with this id (or it was deleted)."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`group-managed-elsewhere`: The group is managed by your directory; remove it there.\n\n`group-in-use`: Rules still use this group; the problem body lists them in `rules`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "group-managed-elsewhere": {
                    "summary": "The group is managed by your directory; remove it there.",
                    "value": {
                      "type": "https://cloudraw.com/problems/group-managed-elsewhere",
                      "code": "group-managed-elsewhere",
                      "title": "group managed elsewhere",
                      "status": 409,
                      "detail": "The group is managed by your directory; remove it there."
                    }
                  },
                  "group-in-use": {
                    "summary": "Rules still use this group; the problem body lists them in `rules`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/group-in-use",
                      "code": "group-in-use",
                      "title": "group in use",
                      "status": 409,
                      "detail": "Rules still use this group; the problem body lists them in rules."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/jit-grants": {
      "get": {
        "tags": [
          "Just-in-time access"
        ],
        "operationId": "listJitGrants",
        "summary": "List temporary access grants",
        "description": "Returns grants created by approved requests: active ones and those that ended (revoked or expired). Not paginated.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "description": "Only grants in this state.",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "revoke_pending",
                "revoked",
                "expired"
              ]
            },
            "example": "active"
          }
        ],
        "responses": {
          "200": {
            "description": "The grants.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/JitGrant"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Opaque cursor for the next page; null on the last page."
                    }
                  },
                  "required": [
                    "items"
                  ]
                },
                "example": {
                  "items": [
                    {
                      "id": "jg_3m0x9k2s8d",
                      "request_id": "jr_5x8k2m0s9d",
                      "subject": {
                        "name": "Noa Peretz",
                        "email": "noa.peretz@example.org",
                        "vendor": "Contoso Systems"
                      },
                      "connection_id": "cx9m2v7d1pa",
                      "resource_name": "erp-db",
                      "approver": "dana.levi@example.com",
                      "window_hours": 4,
                      "started_at": "2026-10-13T09:30:00.000Z",
                      "expires_at": "2026-10-13T13:30:00.000Z",
                      "state": "active",
                      "recording": true,
                      "mfa": true,
                      "ended_at": null,
                      "ended_reason": null,
                      "kind": "vendor",
                      "device_id": null,
                      "claimed_at": null,
                      "claim_pending": true,
                      "controls_enforcement": {
                        "recording": "stored",
                        "mfa": "stored"
                      }
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/jit-grants/{grant_id}": {
      "delete": {
        "tags": [
          "Just-in-time access"
        ],
        "operationId": "revokeJitGrant",
        "summary": "Revoke a temporary access grant",
        "description": "Ends an active grant now: its access is removed and, for a supplier, the single-use identity is deleted. If the removal cannot be confirmed at once, the grant is already unusable from Cloudraw's side, shows `revoke_pending`, and removal is retried automatically; the answer then has `state: pending` and `error: \"revoke_pending\"`. Audited and raises an alert.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "grant_id",
            "in": "path",
            "required": true,
            "description": "Grant id.",
            "schema": {
              "type": "string"
            },
            "example": "jg_3m0x9k2s8d"
          }
        ],
        "responses": {
          "202": {
            "description": "Revoked (`done`) or being retried (`pending`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                },
                "example": {
                  "id": "task_8k2x0m9s1d",
                  "tenant_id": "tq7x2m9k4ab",
                  "state": "done",
                  "result_uri": null,
                  "error": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`grant-not-found`: No grant with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "grant-not-found": {
                    "summary": "No grant with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/grant-not-found",
                      "code": "grant-not-found",
                      "title": "grant not found",
                      "status": 404,
                      "detail": "No grant with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`grant-not-active`: The grant already ended.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "grant-not-active": {
                    "summary": "The grant already ended.",
                    "value": {
                      "type": "https://cloudraw.com/problems/grant-not-active",
                      "code": "grant-not-active",
                      "title": "grant not active",
                      "status": 409,
                      "detail": "The grant already ended."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`revoke-failed`: Unexpected failure; retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "revoke-failed": {
                    "summary": "Unexpected failure; retry.",
                    "value": {
                      "type": "https://cloudraw.com/problems/revoke-failed",
                      "code": "revoke-failed",
                      "title": "revoke failed",
                      "status": 502,
                      "detail": "Unexpected failure; retry."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/jit-grants/{grant_id}/extend": {
      "post": {
        "tags": [
          "Just-in-time access"
        ],
        "operationId": "extendJitGrant",
        "summary": "Extend a temporary access grant",
        "description": "Moves an active grant's expiry later. The total length, counted from `started_at`, can never exceed the JIT policy `max_window_hours` (itself at most 24 hours). Audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "grant_id",
            "in": "path",
            "required": true,
            "description": "Grant id.",
            "schema": {
              "type": "string"
            },
            "example": "jg_3m0x9k2s8d"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "add_hours": {
                    "type": "integer",
                    "description": "Hours to add, 1-24. Default 1.",
                    "minimum": 1,
                    "maximum": 24
                  }
                }
              },
              "example": {
                "add_hours": 2
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The grant with its new `expires_at`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JitGrant"
                },
                "example": {
                  "id": "jg_3m0x9k2s8d",
                  "request_id": "jr_5x8k2m0s9d",
                  "subject": {
                    "name": "Noa Peretz",
                    "email": "noa.peretz@example.org",
                    "vendor": "Contoso Systems"
                  },
                  "connection_id": "cx9m2v7d1pa",
                  "resource_name": "erp-db",
                  "approver": "dana.levi@example.com",
                  "window_hours": 6,
                  "started_at": "2026-10-13T09:30:00.000Z",
                  "expires_at": "2026-10-13T15:30:00.000Z",
                  "state": "active",
                  "recording": true,
                  "mfa": true,
                  "ended_at": null,
                  "ended_reason": null,
                  "kind": "vendor",
                  "device_id": null,
                  "claimed_at": null,
                  "claim_pending": true,
                  "controls_enforcement": {
                    "recording": "stored",
                    "mfa": "stored"
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid-add-hours`: `add_hours` is not a whole number from 1 to 24.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-add-hours": {
                    "summary": "`add_hours` is not a whole number from 1 to 24.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-add-hours",
                      "code": "invalid-add-hours",
                      "title": "invalid add hours",
                      "status": 400,
                      "detail": "add_hours is not a whole number from 1 to 24."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`grant-not-found`: No grant with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "grant-not-found": {
                    "summary": "No grant with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/grant-not-found",
                      "code": "grant-not-found",
                      "title": "grant not found",
                      "status": 404,
                      "detail": "No grant with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`grant-not-active`: The grant already ended.\n\n`extension-exceeds-maximum-window`: The grant would last longer than `max_window_hours` from its start.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "grant-not-active": {
                    "summary": "The grant already ended.",
                    "value": {
                      "type": "https://cloudraw.com/problems/grant-not-active",
                      "code": "grant-not-active",
                      "title": "grant not active",
                      "status": 409,
                      "detail": "The grant already ended."
                    }
                  },
                  "extension-exceeds-maximum-window": {
                    "summary": "The grant would last longer than `max_window_hours` from its start.",
                    "value": {
                      "type": "https://cloudraw.com/problems/extension-exceeds-maximum-window",
                      "code": "extension-exceeds-maximum-window",
                      "title": "extension exceeds maximum window",
                      "status": 409,
                      "detail": "The grant would last longer than max_window_hours from its start."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/jit-policy": {
      "get": {
        "tags": [
          "Just-in-time access"
        ],
        "operationId": "getJitPolicy",
        "summary": "Get the just-in-time access policy",
        "description": "Returns the workspace rules for temporary access: the longest grant, whether a sponsor is required, recording and second-step defaults, whether only trusted devices may get access, and whether your own people may request access from Cloudraw Connect.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "responses": {
          "200": {
            "description": "The policy (defaults when never changed).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JitPolicy"
                },
                "example": {
                  "sponsor_required": true,
                  "record_by_default": true,
                  "block_unmanaged": false,
                  "max_window_hours": 8,
                  "require_mfa": true,
                  "employee_requests": {
                    "enabled": true,
                    "connection_ids": [
                      "cx9m2v7d1pa"
                    ]
                  },
                  "version": 4
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/jit-requests": {
      "get": {
        "tags": [
          "Just-in-time access"
        ],
        "operationId": "listJitRequests",
        "summary": "List access requests",
        "description": "Returns requests for temporary access to an app: from your own people (Cloudraw Connect), from outside suppliers (invite links) and those filed by admins. Filter with `state=pending` to get the ones waiting for a decision. Not paginated.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "description": "Only requests in this state.",
            "schema": {
              "type": "string",
              "enum": [
                "pending_email",
                "pending",
                "approved",
                "denied",
                "cancelled",
                "expired"
              ]
            },
            "example": "pending"
          }
        ],
        "responses": {
          "200": {
            "description": "The requests.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/JitRequest"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Opaque cursor for the next page; null on the last page."
                    }
                  },
                  "required": [
                    "items"
                  ]
                },
                "example": {
                  "items": [
                    {
                      "id": "jr_5x8k2m0s9d",
                      "kind": "vendor",
                      "subject": {
                        "name": "Noa Peretz",
                        "email": "noa.peretz@example.org",
                        "vendor": "Contoso Systems"
                      },
                      "connection_id": "cx9m2v7d1pa",
                      "resource_name": "erp-db",
                      "mode": "access",
                      "window_hours": 4,
                      "reason": "Apply vendor hotfix KB-2291 to the ERP database.",
                      "sponsor": "dana.levi@example.com",
                      "risk": "med",
                      "device_posture": null,
                      "state": "pending",
                      "created_at": "2026-10-13T09:24:11.000Z",
                      "decided_at": null,
                      "decided_by": null,
                      "decided_note": null,
                      "grant_id": null,
                      "requested_by": "vendor-invite:jinv_6k2x9m0s",
                      "via_invite": "jinv_6k2x9m0s",
                      "device": {
                        "name": "NOA-LAPTOP",
                        "os": "Windows 11"
                      },
                      "email_verified": true
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/jit-requests/{request_id}/approve": {
      "post": {
        "tags": [
          "Just-in-time access"
        ],
        "operationId": "approveJitRequest",
        "summary": "Approve an access request",
        "description": "Approves a pending request and creates a time-boxed grant to that one app. For your own person, access is given to the device that asked; for a supplier, a separate single-use identity is created that can reach only that app. The grant ends by itself at `expires_at`. The person who filed a request can never approve it (separation of duties). Audited and raises an alert.\n\n**Token:** full access · **Created by:** owner\n\n**Idempotency:** send `Idempotency-Key`. The answer carries a secret shown once: a retry with the same key answers `409 already-issued` instead of the secret.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "request_id",
            "in": "path",
            "required": true,
            "description": "Access request id.",
            "schema": {
              "type": "string"
            },
            "example": "jr_5x8k2m0s9d"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "window_hours": {
                    "type": "number",
                    "description": "Grant length in hours (rounded, 1-24). Default: the requested window. Capped by the JIT policy `max_window_hours`."
                  },
                  "recording": {
                    "type": "boolean",
                    "description": "Default: the JIT policy `record_by_default`."
                  },
                  "mfa": {
                    "type": "boolean",
                    "description": "Default: the JIT policy `require_mfa`."
                  },
                  "note": {
                    "type": "string",
                    "description": "Up to 300 characters, shown in the request."
                  }
                }
              },
              "example": {
                "window_hours": 2,
                "note": "Approved for the maintenance window only."
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new grant. `enrollment_jwt` appears only for supplier requests an admin filed (shown once).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JitApproval"
                },
                "example": {
                  "id": "jg_3m0x9k2s8d",
                  "request_id": "jr_5x8k2m0s9d",
                  "subject": {
                    "name": "Noa Peretz",
                    "email": "noa.peretz@example.org",
                    "vendor": "Contoso Systems"
                  },
                  "connection_id": "cx9m2v7d1pa",
                  "resource_name": "erp-db",
                  "approver": "dana.levi@example.com",
                  "window_hours": 2,
                  "started_at": "2026-10-13T09:30:00.000Z",
                  "expires_at": "2026-10-13T11:30:00.000Z",
                  "state": "active",
                  "recording": true,
                  "mfa": true,
                  "ended_at": null,
                  "ended_reason": null,
                  "kind": "vendor",
                  "device_id": null,
                  "claimed_at": null,
                  "claim_pending": true,
                  "controls_enforcement": {
                    "recording": "stored",
                    "mfa": "stored"
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid-window-hours`: `window_hours` is not a number.\n\n`invalid-note`: `note` is not text or is longer than 300 characters.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-window-hours": {
                    "summary": "`window_hours` is not a number.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-window-hours",
                      "code": "invalid-window-hours",
                      "title": "invalid window hours",
                      "status": 400,
                      "detail": "window_hours is not a number."
                    }
                  },
                  "invalid-note": {
                    "summary": "`note` is not text or is longer than 300 characters.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-note",
                      "code": "invalid-note",
                      "title": "invalid note",
                      "status": 400,
                      "detail": "note is not text or is longer than 300 characters."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`separation-of-duties`: You filed this request (or it is about you); someone else must approve it.\n\n`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "separation-of-duties": {
                    "summary": "You filed this request (or it is about you); someone else must approve it.",
                    "value": {
                      "type": "https://cloudraw.com/problems/separation-of-duties",
                      "code": "separation-of-duties",
                      "title": "separation of duties",
                      "status": 403,
                      "detail": "You filed this request (or it is about you); someone else must approve it."
                    }
                  },
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`request-not-found`: No request with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "request-not-found": {
                    "summary": "No request with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/request-not-found",
                      "code": "request-not-found",
                      "title": "request not found",
                      "status": 404,
                      "detail": "No request with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`request-already-decided`: The request is not `pending` (already approved, denied, cancelled, expired, or the supplier has not confirmed their e-mail).\n\n`resource-no-longer-exists`: The app was deleted.\n\n`browser-only-app`: The app is recorded and browser-only; temporary direct access would bypass the recording. Use an access rule.\n\n`protected-file-server`: The app is a protected file server reached only through the portal. Use an access rule.\n\n`device-no-longer-enrolled`: The device that asked was removed.\n\n`device-not-trusted`: The JIT policy allows only trusted devices and this device is not trusted now.\n\n`idempotency-key-reuse`: The same `Idempotency-Key` was used with a different body within 24 hours.\n\n`already-issued`: This `Idempotency-Key` already created a secret; it is shown only once. Retry with a new key.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "request-already-decided": {
                    "summary": "The request is not `pending` (already approved, denied, cancelled, expired, or the supplier has not confirmed their e-mail).",
                    "value": {
                      "type": "https://cloudraw.com/problems/request-already-decided",
                      "code": "request-already-decided",
                      "title": "request already decided",
                      "status": 409,
                      "detail": "The request is not pending (already approved, denied, cancelled, expired, or the supplier has not confirmed their e-mail)."
                    }
                  },
                  "resource-no-longer-exists": {
                    "summary": "The app was deleted.",
                    "value": {
                      "type": "https://cloudraw.com/problems/resource-no-longer-exists",
                      "code": "resource-no-longer-exists",
                      "title": "resource no longer exists",
                      "status": 409,
                      "detail": "The app was deleted."
                    }
                  },
                  "browser-only-app": {
                    "summary": "The app is recorded and browser-only; temporary direct access would bypass the recording. Use an access rule.",
                    "value": {
                      "type": "https://cloudraw.com/problems/browser-only-app",
                      "code": "browser-only-app",
                      "title": "browser only app",
                      "status": 409,
                      "detail": "The app is recorded and browser-only; temporary direct access would bypass the recording. Use an access rule."
                    }
                  },
                  "protected-file-server": {
                    "summary": "The app is a protected file server reached only through the portal. Use an access rule.",
                    "value": {
                      "type": "https://cloudraw.com/problems/protected-file-server",
                      "code": "protected-file-server",
                      "title": "protected file server",
                      "status": 409,
                      "detail": "The app is a protected file server reached only through the portal. Use an access rule."
                    }
                  },
                  "device-no-longer-enrolled": {
                    "summary": "The device that asked was removed.",
                    "value": {
                      "type": "https://cloudraw.com/problems/device-no-longer-enrolled",
                      "code": "device-no-longer-enrolled",
                      "title": "device no longer enrolled",
                      "status": 409,
                      "detail": "The device that asked was removed."
                    }
                  },
                  "device-not-trusted": {
                    "summary": "The JIT policy allows only trusted devices and this device is not trusted now.",
                    "value": {
                      "type": "https://cloudraw.com/problems/device-not-trusted",
                      "code": "device-not-trusted",
                      "title": "device not trusted",
                      "status": 409,
                      "detail": "The JIT policy allows only trusted devices and this device is not trusted now."
                    }
                  },
                  "idempotency-key-reuse": {
                    "summary": "The same `Idempotency-Key` was used with a different body within 24 hours.",
                    "value": {
                      "type": "https://cloudraw.com/problems/idempotency-key-reuse",
                      "code": "idempotency-key-reuse",
                      "title": "idempotency key reuse",
                      "status": 409,
                      "detail": "The same Idempotency-Key was used with a different body within 24 hours."
                    }
                  },
                  "already-issued": {
                    "summary": "This `Idempotency-Key` already created a secret; it is shown only once. Retry with a new key.",
                    "value": {
                      "type": "https://cloudraw.com/problems/already-issued",
                      "code": "already-issued",
                      "title": "already issued",
                      "status": 409,
                      "detail": "This Idempotency-Key already created a secret; it is shown only once. Retry with a new key."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`grant-failed`: Cloudraw could not create the access; nothing was granted. Retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "grant-failed": {
                    "summary": "Cloudraw could not create the access; nothing was granted. Retry.",
                    "value": {
                      "type": "https://cloudraw.com/problems/grant-failed",
                      "code": "grant-failed",
                      "title": "grant failed",
                      "status": 502,
                      "detail": "Cloudraw could not create the access; nothing was granted. Retry."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        },
        "x-cloudraw-idempotent": "secret"
      }
    },
    "/v0/tenants/{tenant_id}/jit-requests/{request_id}/deny": {
      "post": {
        "tags": [
          "Just-in-time access"
        ],
        "operationId": "denyJitRequest",
        "summary": "Deny an access request",
        "description": "Denies a pending request. Nothing is granted. Audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "request_id",
            "in": "path",
            "required": true,
            "description": "Access request id.",
            "schema": {
              "type": "string"
            },
            "example": "jr_5x8k2m0s9d"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "note": {
                    "type": "string",
                    "description": "Up to 300 characters, shown in the request."
                  }
                }
              },
              "example": {
                "note": "Please schedule this through the change board."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The decided request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JitRequest"
                },
                "example": {
                  "id": "jr_5x8k2m0s9d",
                  "kind": "vendor",
                  "subject": {
                    "name": "Noa Peretz",
                    "email": "noa.peretz@example.org",
                    "vendor": "Contoso Systems"
                  },
                  "connection_id": "cx9m2v7d1pa",
                  "resource_name": "erp-db",
                  "mode": "access",
                  "window_hours": 4,
                  "reason": "Apply vendor hotfix KB-2291 to the ERP database.",
                  "sponsor": "dana.levi@example.com",
                  "risk": "med",
                  "device_posture": null,
                  "state": "denied",
                  "created_at": "2026-10-13T09:24:11.000Z",
                  "decided_at": "2026-10-13T09:24:11.000Z",
                  "decided_by": "dana.levi@example.com",
                  "decided_note": "Please schedule this through the change board.",
                  "grant_id": null,
                  "requested_by": "vendor-invite:jinv_6k2x9m0s",
                  "via_invite": "jinv_6k2x9m0s",
                  "device": {
                    "name": "NOA-LAPTOP",
                    "os": "Windows 11"
                  },
                  "email_verified": true
                }
              }
            }
          },
          "400": {
            "description": "`invalid-note`: `note` is not text or is longer than 300 characters.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-note": {
                    "summary": "`note` is not text or is longer than 300 characters.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-note",
                      "code": "invalid-note",
                      "title": "invalid note",
                      "status": 400,
                      "detail": "note is not text or is longer than 300 characters."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`request-not-found`: No request with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "request-not-found": {
                    "summary": "No request with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/request-not-found",
                      "code": "request-not-found",
                      "title": "request not found",
                      "status": 404,
                      "detail": "No request with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`request-already-decided`: The request is not `pending`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "request-already-decided": {
                    "summary": "The request is not `pending`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/request-already-decided",
                      "code": "request-already-decided",
                      "title": "request already decided",
                      "status": 409,
                      "detail": "The request is not pending."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/kpi": {
      "get": {
        "tags": [
          "Dashboard tiles"
        ],
        "operationId": "getKpiValues",
        "summary": "Get tile values",
        "description": "The current value of up to 20 tiles, each computed exactly like its detail page (for example `devices_online` = the Map's online devices). An id that is not in the catalog refuses the call (400); a tile your role may not use is left out and listed in `dropped`. A tile that cannot be computed carries `error` without failing the others. Values are cached for up to 5 minutes.\n\n**Token:** read-only or full access · **Created by:** owner or security admin\n\n**Rate limit:** 60 dashboard-tile calls per minute per person.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "ids",
            "in": "query",
            "required": false,
            "description": "Comma-separated tile ids.",
            "schema": {
              "type": "string"
            },
            "example": "devices_online,devices_compliant"
          },
          {
            "name": "range",
            "in": "query",
            "required": false,
            "description": "Trend length: `7d` (default) or `30d`.",
            "schema": {
              "type": "string",
              "enum": [
                "7d",
                "30d"
              ]
            },
            "example": "7d"
          }
        ],
        "responses": {
          "200": {
            "description": "The values.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KpiValues"
                },
                "example": {
                  "range": "7d",
                  "items": [
                    {
                      "id": "devices_online",
                      "value": 21,
                      "unit": "ratio",
                      "state": "ok",
                      "counts": {
                        "total": 23
                      },
                      "trend": {
                        "step": "1d",
                        "points": [
                          {
                            "t": "2026-10-28",
                            "v": 20
                          }
                        ]
                      },
                      "as_of": "2026-10-29T14:00:00.000Z"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "`invalid-range`: `range` is not `7d` or `30d`.\n\n`unknown-tile`: An id is not a tile from the catalog, or more than 20 tiles were asked for.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-range": {
                    "summary": "`range` is not `7d` or `30d`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-range",
                      "code": "invalid-range",
                      "title": "invalid range",
                      "status": 400,
                      "detail": "range is not 7d or 30d."
                    }
                  },
                  "unknown-tile": {
                    "summary": "An id is not a tile from the catalog, or more than 20 tiles were asked for.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unknown-tile",
                      "code": "unknown-tile",
                      "title": "unknown tile",
                      "status": 400,
                      "detail": "An id is not a tile from the catalog, or more than 20 tiles were asked for."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate-limited`: Too many calls; wait `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "rate-limited": {
                    "summary": "Too many calls; wait `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/rate-limited",
                      "code": "rate-limited",
                      "title": "rate limited",
                      "status": 429,
                      "detail": "Too many calls; wait Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        },
        "x-cloudraw-rate-limit": "60 dashboard-tile calls per minute per person."
      }
    },
    "/v0/tenants/{tenant_id}/kpi/catalog": {
      "get": {
        "tags": [
          "Dashboard tiles"
        ],
        "operationId": "getKpiCatalog",
        "summary": "List the dashboard tiles",
        "description": "The tiles you may add to the dashboard, with their unit and area, and the starting layouts. Billing tiles (seats, monthly active users) need the owner role; second-step coverage needs owner or security admin.\n\n**Token:** read-only or full access · **Created by:** owner or security admin\n\n**Rate limit:** 60 dashboard-tile calls per minute per person.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "responses": {
          "200": {
            "description": "The catalog.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KpiCatalog"
                },
                "example": {
                  "items": [
                    {
                      "id": "devices_online",
                      "area": "devices",
                      "unit": "ratio",
                      "module": null,
                      "trend": true,
                      "simple_ok": true,
                      "map": true
                    }
                  ],
                  "presets": {
                    "map": [
                      {
                        "id": "devices_online",
                        "size": 1
                      }
                    ]
                  },
                  "default_preset": "map",
                  "states": [
                    "ok",
                    "warn",
                    "bad",
                    "not_available",
                    "building",
                    "fewer_than_5"
                  ],
                  "limits": {
                    "ids": 20,
                    "layout": 24,
                    "ranges": [
                      "7d",
                      "30d"
                    ],
                    "cache_s": 300,
                    "k_min": 5
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate-limited`: Too many calls; wait `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "rate-limited": {
                    "summary": "Too many calls; wait `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/rate-limited",
                      "code": "rate-limited",
                      "title": "rate limited",
                      "status": 429,
                      "detail": "Too many calls; wait Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        },
        "x-cloudraw-rate-limit": "60 dashboard-tile calls per minute per person."
      }
    },
    "/v0/tenants/{tenant_id}/notifications": {
      "get": {
        "tags": [
          "Alerts"
        ],
        "operationId": "listAlerts",
        "summary": "List alerts",
        "description": "Returns the console alerts (the bell in the Cloudraw console): connector health, device trust changes, access requests, security events and more, newest first, each with its triage state. Not paginated: use `limit` (at most 500) and the filters.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "unread",
            "in": "query",
            "required": false,
            "description": "Only alerts not yet marked read.",
            "schema": {
              "type": "string",
              "enum": [
                "true"
              ]
            },
            "example": "true"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Triage filter: `open` (= `new` + `acknowledged`, the work queue), `all` (default), or a comma-separated list of statuses (`new,acknowledged,resolved,dismissed`).",
            "schema": {
              "type": "string"
            },
            "example": "open"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "`severity` = high severity first (then newest). Default: newest first.",
            "schema": {
              "type": "string",
              "enum": [
                "severity"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum items, newest first. Default 100, at most 500.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            },
            "example": 100
          }
        ],
        "responses": {
          "200": {
            "description": "The alerts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationList"
                },
                "example": {
                  "items": [
                    {
                      "id": "ntf_4k2x9m0s8d",
                      "severity": "bad",
                      "category": "security",
                      "action": "security_event",
                      "data": {
                        "event": "sev_9x2k0m8s1d"
                      },
                      "message": "Blocked: Port scan from unmanaged device",
                      "view": "soc",
                      "param": null,
                      "read": false,
                      "created_at": "2026-10-13T09:24:11.000Z",
                      "triage": {
                        "status": "new",
                        "assignee": null,
                        "acknowledged_by": null,
                        "acknowledged_at": null,
                        "resolution": null,
                        "suppressed_by": null,
                        "history": []
                      },
                      "resolved": false,
                      "resolved_at": null
                    }
                  ],
                  "unread": 3,
                  "next_page": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/notifications/{notification_id}/acknowledge": {
      "post": {
        "tags": [
          "Alerts"
        ],
        "operationId": "acknowledgeAlert",
        "summary": "Acknowledge an alert",
        "description": "Takes ownership of a `new` alert: status becomes `acknowledged` and `assignee` is set (the caller unless you name someone). The step is added to the alert's triage history, written to the audit log and streamed to your SIEM destinations. The alert is also marked read. Triage never deletes an alert.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "notification_id",
            "in": "path",
            "required": true,
            "description": "Alert (notification) id.",
            "schema": {
              "type": "string"
            },
            "example": "ntf_4k2x9m0s8d"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "assignee": {
                    "type": "string",
                    "description": "Who owns it (up to 160 characters). Default: the caller."
                  },
                  "note": {
                    "type": "string",
                    "description": "Up to 1000 characters."
                  }
                }
              },
              "example": {
                "assignee": "omer.katz@example.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The alert with its new triage state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertTriageResult"
                },
                "example": {
                  "id": "ntf_4k2x9m0s8d",
                  "kind": "notification",
                  "severity": "bad",
                  "triage": {
                    "status": "acknowledged",
                    "assignee": "dana.levi@example.com",
                    "acknowledged_by": "dana.levi@example.com",
                    "acknowledged_at": "2026-10-13T09:24:11.000Z",
                    "resolution": null,
                    "suppressed_by": null,
                    "history": [
                      {
                        "at": "2026-10-13T09:24:11.000Z",
                        "by": "dana.levi@example.com",
                        "action": "acknowledge",
                        "from": "new",
                        "to": "acknowledged",
                        "reason": null,
                        "note": null
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`notification-not-found`: No alert with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "notification-not-found": {
                    "summary": "No alert with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/notification-not-found",
                      "code": "notification-not-found",
                      "title": "notification not found",
                      "status": 404,
                      "detail": "No alert with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`invalid-transition`: The alert is not `new`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-transition": {
                    "summary": "The alert is not `new`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-transition",
                      "code": "invalid-transition",
                      "title": "invalid transition",
                      "status": 409,
                      "detail": "The alert is not new."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/notifications/{notification_id}/dismiss": {
      "post": {
        "tags": [
          "Alerts"
        ],
        "operationId": "dismissAlert",
        "summary": "Dismiss an alert",
        "description": "Closes a `new` or `acknowledged` alert as not needing action (status `dismissed`). A `reason` is required, and a `note` too when the alert severity is `bad`. The step is added to the alert's triage history, written to the audit log and streamed to your SIEM destinations. The alert is also marked read. Triage never deletes an alert.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "notification_id",
            "in": "path",
            "required": true,
            "description": "Alert (notification) id.",
            "schema": {
              "type": "string"
            },
            "example": "ntf_4k2x9m0s8d"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string",
                    "enum": [
                      "false_positive",
                      "expected_activity",
                      "benign",
                      "duplicate",
                      "accepted_risk"
                    ]
                  },
                  "note": {
                    "type": "string",
                    "description": "Why (up to 1000 characters). Required when the alert severity is `bad`."
                  }
                },
                "required": [
                  "reason"
                ]
              },
              "example": {
                "reason": "expected_activity",
                "note": "Quarterly penetration test by our vendor."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The alert with its new triage state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertTriageResult"
                },
                "example": {
                  "id": "ntf_4k2x9m0s8d",
                  "kind": "notification",
                  "severity": "bad",
                  "triage": {
                    "status": "dismissed",
                    "assignee": null,
                    "acknowledged_by": null,
                    "acknowledged_at": null,
                    "resolution": {
                      "kind": "dismissed",
                      "reason": "expected_activity",
                      "note": "Quarterly penetration test by our vendor.",
                      "by": "dana.levi@example.com",
                      "at": "2026-10-13T09:24:11.000Z"
                    },
                    "suppressed_by": null,
                    "history": [
                      {
                        "at": "2026-10-13T09:24:11.000Z",
                        "by": "dana.levi@example.com",
                        "action": "dismiss",
                        "from": "new",
                        "to": "dismissed",
                        "reason": "expected_activity",
                        "note": null
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "`reason-required`: `reason` is missing or not one of the allowed values.\n\n`note-required`: The alert severity is `bad` and no `note` was given.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "reason-required": {
                    "summary": "`reason` is missing or not one of the allowed values.",
                    "value": {
                      "type": "https://cloudraw.com/problems/reason-required",
                      "code": "reason-required",
                      "title": "reason required",
                      "status": 400,
                      "detail": "reason is missing or not one of the allowed values."
                    }
                  },
                  "note-required": {
                    "summary": "The alert severity is `bad` and no `note` was given.",
                    "value": {
                      "type": "https://cloudraw.com/problems/note-required",
                      "code": "note-required",
                      "title": "note required",
                      "status": 400,
                      "detail": "The alert severity is bad and no note was given."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`notification-not-found`: No alert with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "notification-not-found": {
                    "summary": "No alert with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/notification-not-found",
                      "code": "notification-not-found",
                      "title": "notification not found",
                      "status": 404,
                      "detail": "No alert with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`invalid-transition`: The alert is already resolved or dismissed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-transition": {
                    "summary": "The alert is already resolved or dismissed.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-transition",
                      "code": "invalid-transition",
                      "title": "invalid transition",
                      "status": 409,
                      "detail": "The alert is already resolved or dismissed."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/notifications/{notification_id}/read": {
      "post": {
        "tags": [
          "Alerts"
        ],
        "operationId": "markAlertRead",
        "summary": "Mark an alert read",
        "description": "Marks one alert read in the console inbox. Does not change its triage status. Not audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "notification_id",
            "in": "path",
            "required": true,
            "description": "Alert (notification) id.",
            "schema": {
              "type": "string"
            },
            "example": "ntf_4k2x9m0s8d"
          }
        ],
        "responses": {
          "200": {
            "description": "The alert.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Notification"
                },
                "example": {
                  "id": "ntf_4k2x9m0s8d",
                  "severity": "bad",
                  "category": "security",
                  "action": "security_event",
                  "data": {
                    "event": "sev_9x2k0m8s1d"
                  },
                  "message": "Blocked: Port scan from unmanaged device",
                  "view": "soc",
                  "param": null,
                  "read": true,
                  "created_at": "2026-10-13T09:24:11.000Z",
                  "triage": {
                    "status": "new",
                    "assignee": null,
                    "acknowledged_by": null,
                    "acknowledged_at": null,
                    "resolution": null,
                    "suppressed_by": null,
                    "history": []
                  },
                  "resolved": false,
                  "resolved_at": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`notification-not-found`: No alert with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "notification-not-found": {
                    "summary": "No alert with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/notification-not-found",
                      "code": "notification-not-found",
                      "title": "notification not found",
                      "status": 404,
                      "detail": "No alert with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/notifications/{notification_id}/reopen": {
      "post": {
        "tags": [
          "Alerts"
        ],
        "operationId": "reopenAlert",
        "summary": "Reopen an alert",
        "description": "Puts a `resolved` or `dismissed` alert back to `new` and clears its resolution. The step is added to the alert's triage history, written to the audit log and streamed to your SIEM destinations. Triage never deletes an alert.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "notification_id",
            "in": "path",
            "required": true,
            "description": "Alert (notification) id.",
            "schema": {
              "type": "string"
            },
            "example": "ntf_4k2x9m0s8d"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "note": {
                    "type": "string",
                    "description": "Up to 1000 characters."
                  }
                }
              },
              "example": {
                "note": "Recurred after the fix."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The alert with its new triage state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertTriageResult"
                },
                "example": {
                  "id": "ntf_4k2x9m0s8d",
                  "kind": "notification",
                  "severity": "bad",
                  "triage": {
                    "status": "new",
                    "assignee": null,
                    "acknowledged_by": null,
                    "acknowledged_at": null,
                    "resolution": null,
                    "suppressed_by": null,
                    "history": [
                      {
                        "at": "2026-10-13T09:24:11.000Z",
                        "by": "dana.levi@example.com",
                        "action": "reopen",
                        "from": "resolved",
                        "to": "new",
                        "reason": null,
                        "note": "Recurred after the fix."
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`notification-not-found`: No alert with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "notification-not-found": {
                    "summary": "No alert with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/notification-not-found",
                      "code": "notification-not-found",
                      "title": "notification not found",
                      "status": 404,
                      "detail": "No alert with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`invalid-transition`: The alert is not resolved or dismissed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-transition": {
                    "summary": "The alert is not resolved or dismissed.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-transition",
                      "code": "invalid-transition",
                      "title": "invalid transition",
                      "status": 409,
                      "detail": "The alert is not resolved or dismissed."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/notifications/{notification_id}/resolve": {
      "post": {
        "tags": [
          "Alerts"
        ],
        "operationId": "resolveAlert",
        "summary": "Resolve an alert",
        "description": "Closes a `new` or `acknowledged` alert as handled (status `resolved`). The step is added to the alert's triage history, written to the audit log and streamed to your SIEM destinations. The alert is also marked read. Triage never deletes an alert.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "notification_id",
            "in": "path",
            "required": true,
            "description": "Alert (notification) id.",
            "schema": {
              "type": "string"
            },
            "example": "ntf_4k2x9m0s8d"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "note": {
                    "type": "string",
                    "description": "Up to 1000 characters."
                  }
                }
              },
              "example": {
                "note": "Device re-encrypted; access works again."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The alert with its new triage state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertTriageResult"
                },
                "example": {
                  "id": "ntf_4k2x9m0s8d",
                  "kind": "notification",
                  "severity": "bad",
                  "triage": {
                    "status": "resolved",
                    "assignee": null,
                    "acknowledged_by": null,
                    "acknowledged_at": null,
                    "resolution": {
                      "kind": "resolved",
                      "reason": null,
                      "note": "Device re-encrypted; access works again.",
                      "by": "dana.levi@example.com",
                      "at": "2026-10-13T09:24:11.000Z"
                    },
                    "suppressed_by": null,
                    "history": [
                      {
                        "at": "2026-10-13T09:24:11.000Z",
                        "by": "dana.levi@example.com",
                        "action": "resolve",
                        "from": "new",
                        "to": "resolved",
                        "reason": null,
                        "note": null
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`notification-not-found`: No alert with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "notification-not-found": {
                    "summary": "No alert with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/notification-not-found",
                      "code": "notification-not-found",
                      "title": "notification not found",
                      "status": 404,
                      "detail": "No alert with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`invalid-transition`: The alert is already resolved or dismissed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-transition": {
                    "summary": "The alert is already resolved or dismissed.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-transition",
                      "code": "invalid-transition",
                      "title": "invalid transition",
                      "status": 409,
                      "detail": "The alert is already resolved or dismissed."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/people": {
      "get": {
        "tags": [
          "People"
        ],
        "operationId": "listPeople",
        "summary": "List people",
        "description": "Returns every person in the workspace with their groups, sign-in state, last activity and device count. The list is not paginated (it is bounded by your plan's seat limit); filter with `group` or `q`. People who already have a sign-in account but are not listed yet are added in the background, so a later call may show more.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "group",
            "in": "query",
            "required": false,
            "description": "Only members of this group id.",
            "schema": {
              "type": "string"
            },
            "example": "g3k9d0s7aa"
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Case-insensitive text search in e-mail and name.",
            "schema": {
              "type": "string"
            },
            "example": "dana"
          }
        ],
        "responses": {
          "200": {
            "description": "All matching people.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonList"
                },
                "example": {
                  "items": [
                    {
                      "id": "pz81kd03mna",
                      "email": "dana.levi@example.com",
                      "name": "Dana Levi",
                      "groups": [
                        "g3k9d0s7aa"
                      ],
                      "created_by_integrator": null,
                      "idp": "cloudraw",
                      "mfa": false,
                      "suspended": false,
                      "quarantined": false,
                      "quarantined_at": null,
                      "quarantine_reason": null,
                      "created_at": "2026-09-20T07:41:02.000Z",
                      "last_seen": "2026-10-13T09:24:11.000Z",
                      "last_seen_via": "DANA-LAPTOP",
                      "device_count": 1,
                      "state": "active",
                      "invited_at": "2026-09-20T07:41:10.000Z",
                      "invite_count": 1,
                      "ad_groups_synced_at": null,
                      "files_security": null,
                      "via": null,
                      "requested_at": null,
                      "join_link_id": null,
                      "sign_in": {
                        "method": "cloudraw",
                        "second_factor": "email_code",
                        "method_source": "linked"
                      },
                      "idp_links": [],
                      "idp_links_checked_at": null,
                      "sign_in_conflict": null,
                      "phone_masked": null,
                      "sms_codes": false,
                      "second_factors": [
                        "email_code"
                      ],
                      "second_factors_checked_at": "2026-10-12T18:00:00.000Z"
                    }
                  ],
                  "next_page": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      },
      "post": {
        "tags": [
          "People"
        ],
        "operationId": "createPerson",
        "summary": "Create a person",
        "description": "Adds a person to the workspace and takes a seat. No e-mail is sent: call Invite a person afterwards to send the sign-in invitation (or use Bulk invite, which creates and invites in one call). Group ids are stored as given; they are not checked against existing groups.\n\n**Token:** full access · **Created by:** owner\n\n**Idempotency:** send `Idempotency-Key` to retry safely — the same key and body within 24 h returns the first answer.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "description": "E-mail address, unique in the workspace. Up to 160 characters are kept.",
                    "format": "email"
                  },
                  "name": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Display name; up to 120 characters are kept."
                  },
                  "groups": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Group ids (up to 100 kept)."
                  },
                  "idp": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Optional label for how the person signs in (up to 60 characters)."
                  },
                  "mfa": {
                    "type": "boolean",
                    "description": "Admin-set MFA flag. Default false."
                  }
                },
                "required": [
                  "email"
                ]
              },
              "example": {
                "email": "omer.katz@example.com",
                "name": "Omer Katz",
                "groups": [
                  "g3k9d0s7aa"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Person"
                },
                "example": {
                  "id": "p4hd8s0qk2l",
                  "email": "omer.katz@example.com",
                  "name": "Omer Katz",
                  "groups": [
                    "g3k9d0s7aa"
                  ],
                  "created_by_integrator": null,
                  "idp": null,
                  "mfa": false,
                  "suspended": false,
                  "quarantined": false,
                  "quarantined_at": null,
                  "quarantine_reason": null,
                  "created_at": "2026-10-13T09:24:11.000Z",
                  "last_seen": null,
                  "last_seen_via": null,
                  "device_count": 0,
                  "state": "not_invited",
                  "invited_at": null,
                  "invite_count": 0,
                  "ad_groups_synced_at": null,
                  "files_security": null,
                  "via": null,
                  "requested_at": null,
                  "join_link_id": null,
                  "sign_in": null,
                  "idp_links": [],
                  "idp_links_checked_at": null,
                  "sign_in_conflict": null,
                  "phone_masked": null,
                  "sms_codes": false,
                  "second_factors": null,
                  "second_factors_checked_at": null
                }
              }
            }
          },
          "400": {
            "description": "`valid-email-required`: `email` is missing or not an e-mail address.\n\n`groups-must-be-an-array`: `groups` is not an array.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "valid-email-required": {
                    "summary": "`email` is missing or not an e-mail address.",
                    "value": {
                      "type": "https://cloudraw.com/problems/valid-email-required",
                      "code": "valid-email-required",
                      "title": "valid email required",
                      "status": 400,
                      "detail": "email is missing or not an e-mail address."
                    }
                  },
                  "groups-must-be-an-array": {
                    "summary": "`groups` is not an array.",
                    "value": {
                      "type": "https://cloudraw.com/problems/groups-must-be-an-array",
                      "code": "groups-must-be-an-array",
                      "title": "groups must be an array",
                      "status": 400,
                      "detail": "groups is not an array."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`seat-quota-reached`: All seats of the plan are taken.\n\n`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "seat-quota-reached": {
                    "summary": "All seats of the plan are taken.",
                    "value": {
                      "type": "https://cloudraw.com/problems/seat-quota-reached",
                      "code": "seat-quota-reached",
                      "title": "seat quota reached",
                      "status": 403,
                      "detail": "All seats of the plan are taken."
                    }
                  },
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`person-already-exists`: Another person already has this e-mail address.\n\n`idempotency-key-reuse`: The same `Idempotency-Key` was used with a different body within 24 hours.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "person-already-exists": {
                    "summary": "Another person already has this e-mail address.",
                    "value": {
                      "type": "https://cloudraw.com/problems/person-already-exists",
                      "code": "person-already-exists",
                      "title": "person already exists",
                      "status": 409,
                      "detail": "Another person already has this e-mail address."
                    }
                  },
                  "idempotency-key-reuse": {
                    "summary": "The same `Idempotency-Key` was used with a different body within 24 hours.",
                    "value": {
                      "type": "https://cloudraw.com/problems/idempotency-key-reuse",
                      "code": "idempotency-key-reuse",
                      "title": "idempotency key reuse",
                      "status": 409,
                      "detail": "The same Idempotency-Key was used with a different body within 24 hours."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        },
        "x-cloudraw-idempotent": true
      }
    },
    "/v0/tenants/{tenant_id}/people:bulk-invite": {
      "post": {
        "tags": [
          "People"
        ],
        "operationId": "bulkInvitePeople",
        "summary": "Bulk invite people",
        "description": "Creates (or reuses) a person for each e-mail address, adds them to the given groups and sends each one the sign-in invitation. Rows are processed one by one and each gets its own outcome; one bad row does not stop the others. Existing people are added to the groups too, but are not re-invited if they are already active, suspended, waiting for approval or were invited in the last minute. In a workspace that signs in with its own identity provider people are created but no e-mail is sent (`federated-sign-in`). Audited.\n\n**Token:** full access · **Created by:** owner\n\n**Rate limit:** 10 bulk invites per hour per workspace (counted per clock hour).",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Send either `emails` or `people` (1-200 rows).",
                "properties": {
                  "emails": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "email"
                    },
                    "description": "E-mail addresses, 1-200."
                  },
                  "people": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "email": {
                          "type": "string",
                          "format": "email"
                        },
                        "name": {
                          "type": "string",
                          "description": "Display name for a new person."
                        }
                      },
                      "required": [
                        "email"
                      ]
                    },
                    "description": "People with optional names, 1-200 (used instead of `emails`)."
                  },
                  "groups": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Group ids every row is added to; each must exist."
                  }
                }
              },
              "example": {
                "people": [
                  {
                    "email": "omer.katz@example.com",
                    "name": "Omer Katz"
                  },
                  {
                    "email": "noa.cohen@example.com"
                  }
                ],
                "groups": [
                  "g3k9d0s7aa"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-row results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkInviteResult"
                },
                "example": {
                  "results": [
                    {
                      "email": "omer.katz@example.com",
                      "person_id": "p4hd8s0qk2l",
                      "outcome": "invited"
                    },
                    {
                      "email": "noa.cohen@example.com",
                      "person_id": null,
                      "outcome": "seat-quota-reached"
                    }
                  ],
                  "counts": {
                    "invited": 1,
                    "seat-quota-reached": 1
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid-bulk-invite`: No `emails` / `people` list, more than 200 rows, or an unknown group id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-bulk-invite": {
                    "summary": "No `emails` / `people` list, more than 200 rows, or an unknown group id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-bulk-invite",
                      "code": "invalid-bulk-invite",
                      "title": "invalid bulk invite",
                      "status": 400,
                      "detail": "No emails / people list, more than 200 rows, or an unknown group id."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`too-many-bulk-invites`: More than 10 bulk invites this hour; `retry_after_s` in the body says when the hour ends.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "too-many-bulk-invites": {
                    "summary": "More than 10 bulk invites this hour; `retry_after_s` in the body says when the hour ends.",
                    "value": {
                      "type": "https://cloudraw.com/problems/too-many-bulk-invites",
                      "code": "too-many-bulk-invites",
                      "title": "too many bulk invites",
                      "status": 429,
                      "detail": "More than 10 bulk invites this hour; retry_after_s in the body says when the hour ends."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        },
        "x-cloudraw-rate-limit": "10 bulk invites per hour per workspace (counted per clock hour)."
      }
    },
    "/v0/tenants/{tenant_id}/people/{person_id}": {
      "get": {
        "tags": [
          "People"
        ],
        "operationId": "getPerson",
        "summary": "Get a person",
        "description": "Returns one person: groups, sign-in state and method, last activity, device count and security flags.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "person_id",
            "in": "path",
            "required": true,
            "description": "Person id (from List people).",
            "schema": {
              "type": "string"
            },
            "example": "pz81kd03mna"
          }
        ],
        "responses": {
          "200": {
            "description": "The person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Person"
                },
                "example": {
                  "id": "pz81kd03mna",
                  "email": "dana.levi@example.com",
                  "name": "Dana Levi",
                  "groups": [
                    "g3k9d0s7aa"
                  ],
                  "created_by_integrator": null,
                  "idp": "cloudraw",
                  "mfa": false,
                  "suspended": false,
                  "quarantined": false,
                  "quarantined_at": null,
                  "quarantine_reason": null,
                  "created_at": "2026-09-20T07:41:02.000Z",
                  "last_seen": "2026-10-13T09:24:11.000Z",
                  "last_seen_via": "DANA-LAPTOP",
                  "device_count": 1,
                  "state": "active",
                  "invited_at": "2026-09-20T07:41:10.000Z",
                  "invite_count": 1,
                  "ad_groups_synced_at": null,
                  "files_security": null,
                  "via": null,
                  "requested_at": null,
                  "join_link_id": null,
                  "sign_in": {
                    "method": "cloudraw",
                    "second_factor": "email_code",
                    "method_source": "linked"
                  },
                  "idp_links": [],
                  "idp_links_checked_at": null,
                  "sign_in_conflict": null,
                  "phone_masked": null,
                  "sms_codes": false,
                  "second_factors": [
                    "email_code"
                  ],
                  "second_factors_checked_at": "2026-10-12T18:00:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`person-not-found`: No person with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "person-not-found": {
                    "summary": "No person with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/person-not-found",
                      "code": "person-not-found",
                      "title": "person not found",
                      "status": 404,
                      "detail": "No person with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      },
      "patch": {
        "tags": [
          "People"
        ],
        "operationId": "updatePerson",
        "summary": "Update a person",
        "description": "Changes a person's name, e-mail, groups, MFA flag or suspension. Send only the fields to change. `groups` replaces the whole list; to add or remove single groups use Change group membership. Suspending a person immediately cuts all their device and browser sessions, ends their portal sign-ins and revokes temporary access; the answer then carries `sessions_cut`. Un-suspending restores access through their groups. Audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "person_id",
            "in": "path",
            "required": true,
            "description": "Person id (from List people).",
            "schema": {
              "type": "string"
            },
            "example": "pz81kd03mna"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Display name; up to 120 characters are kept."
                  },
                  "email": {
                    "type": "string",
                    "description": "New e-mail address (stored lower-case). This decides which sign-in account belongs to the person.",
                    "format": "email"
                  },
                  "groups": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "The complete new list of group ids (up to 100 kept). Active Directory groups cannot be added or removed here."
                  },
                  "mfa": {
                    "type": "boolean"
                  },
                  "suspended": {
                    "type": "boolean",
                    "description": "true = suspend (cuts every session now); false = restore."
                  }
                }
              },
              "example": {
                "suspended": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonUpdated"
                },
                "example": {
                  "id": "pz81kd03mna",
                  "email": "dana.levi@example.com",
                  "name": "Dana Levi",
                  "groups": [
                    "g3k9d0s7aa"
                  ],
                  "created_by_integrator": null,
                  "idp": "cloudraw",
                  "mfa": false,
                  "suspended": true,
                  "quarantined": false,
                  "quarantined_at": null,
                  "quarantine_reason": null,
                  "created_at": "2026-09-20T07:41:02.000Z",
                  "last_seen": "2026-10-13T09:24:11.000Z",
                  "last_seen_via": "DANA-LAPTOP",
                  "device_count": 1,
                  "state": "suspended",
                  "invited_at": "2026-09-20T07:41:10.000Z",
                  "invite_count": 1,
                  "ad_groups_synced_at": null,
                  "files_security": null,
                  "via": null,
                  "requested_at": null,
                  "join_link_id": null,
                  "sign_in": {
                    "method": "cloudraw",
                    "second_factor": "email_code",
                    "method_source": "linked"
                  },
                  "idp_links": [],
                  "idp_links_checked_at": null,
                  "sign_in_conflict": null,
                  "phone_masked": null,
                  "sms_codes": false,
                  "second_factors": [
                    "email_code"
                  ],
                  "second_factors_checked_at": "2026-10-12T18:00:00.000Z",
                  "sessions_cut": 2
                }
              }
            }
          },
          "400": {
            "description": "`valid-email-required`: `email` is not an e-mail address.\n\n`groups-must-be-an-array`: `groups` is not an array.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "valid-email-required": {
                    "summary": "`email` is not an e-mail address.",
                    "value": {
                      "type": "https://cloudraw.com/problems/valid-email-required",
                      "code": "valid-email-required",
                      "title": "valid email required",
                      "status": 400,
                      "detail": "email is not an e-mail address."
                    }
                  },
                  "groups-must-be-an-array": {
                    "summary": "`groups` is not an array.",
                    "value": {
                      "type": "https://cloudraw.com/problems/groups-must-be-an-array",
                      "code": "groups-must-be-an-array",
                      "title": "groups must be an array",
                      "status": 400,
                      "detail": "groups is not an array."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`person-not-found`: No person with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "person-not-found": {
                    "summary": "No person with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/person-not-found",
                      "code": "person-not-found",
                      "title": "person not found",
                      "status": 404,
                      "detail": "No person with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`person-already-exists`: Another person already has this e-mail address.\n\n`group-managed-elsewhere`: The change would add or remove an Active Directory group; those take their members from Active Directory.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "person-already-exists": {
                    "summary": "Another person already has this e-mail address.",
                    "value": {
                      "type": "https://cloudraw.com/problems/person-already-exists",
                      "code": "person-already-exists",
                      "title": "person already exists",
                      "status": 409,
                      "detail": "Another person already has this e-mail address."
                    }
                  },
                  "group-managed-elsewhere": {
                    "summary": "The change would add or remove an Active Directory group; those take their members from Active Directory.",
                    "value": {
                      "type": "https://cloudraw.com/problems/group-managed-elsewhere",
                      "code": "group-managed-elsewhere",
                      "title": "group managed elsewhere",
                      "status": 409,
                      "detail": "The change would add or remove an Active Directory group; those take their members from Active Directory."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      },
      "delete": {
        "tags": [
          "People"
        ],
        "operationId": "deletePerson",
        "summary": "Delete a person",
        "description": "Removes the person and frees their seat. Their devices stay enrolled but lose every grant at once, their location history is deleted, and their Cloudraw sign-in account (if any) is deleted too, so they cannot sign in again unless re-invited. Deleting a person who is waiting for approval rejects their sign-up; no e-mail is sent. Audited. The work is done when the call returns: the task is already `done`.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "person_id",
            "in": "path",
            "required": true,
            "description": "Person id (from List people).",
            "schema": {
              "type": "string"
            },
            "example": "pz81kd03mna"
          }
        ],
        "responses": {
          "202": {
            "description": "Deleted. The task is already in state `done`. `signin_account` says what happened to the person's Cloudraw sign-in account; `idp_links_removed` whether its identity-provider links are gone.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Task"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "signin_account": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "enum": [
                            "deleted",
                            "already-gone",
                            "not-in-workspace",
                            "delete-failed",
                            null
                          ],
                          "description": "`deleted` = the linked sign-in account was deleted; `already-gone` = it no longer existed; `not-in-workspace` = it belongs to another workspace and was left alone; `delete-failed` = the sign-in service failed and the account is still there (remove it from Settings → Users); null = the person had no sign-in account."
                        },
                        "idp_links_removed": {
                          "type": "boolean",
                          "description": "True when no identity-provider (Microsoft / Google / OIDC) link can sign the person back in: `deleted` or `already-gone`."
                        }
                      },
                      "required": [
                        "signin_account",
                        "idp_links_removed"
                      ]
                    }
                  ]
                },
                "example": {
                  "id": "task_8k2m0x9s1d",
                  "tenant_id": "tq7x2m9k4ab",
                  "state": "done",
                  "result_uri": null,
                  "error": null,
                  "signin_account": "deleted",
                  "idp_links_removed": true
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`person-not-found`: No person with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "person-not-found": {
                    "summary": "No person with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/person-not-found",
                      "code": "person-not-found",
                      "title": "person not found",
                      "status": 404,
                      "detail": "No person with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/people/{person_id}/access": {
      "get": {
        "tags": [
          "People"
        ],
        "operationId": "getPersonAccess",
        "summary": "Get a person's effective access",
        "description": "Explains what a person can reach right now. For each of their enrolled devices it lists the apps and private networks granted (and by which access rule), and the ones a rule would grant through their groups but a device condition blocks (missing posture, untrusted device, suspended person). It also lists the browser portal apps they see and why others are hidden. Computed at call time; nothing is changed.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "person_id",
            "in": "path",
            "required": true,
            "description": "Person id (from List people).",
            "schema": {
              "type": "string"
            },
            "example": "pz81kd03mna"
          }
        ],
        "responses": {
          "200": {
            "description": "Effective access.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonAccess"
                },
                "example": {
                  "person_id": "pz81kd03mna",
                  "suspended": false,
                  "groups": [
                    "g3k9d0s7aa"
                  ],
                  "devices": [
                    {
                      "device_id": "dvc_5mxq2b7r8k",
                      "device_name": "DANA-LAPTOP",
                      "trust": "trusted",
                      "quarantined": false,
                      "posture_freshness": "fresh",
                      "granted": [
                        {
                          "kind": "connection",
                          "id": "cx9m2v7d1pa",
                          "name": "Finance ERP",
                          "granted_by": {
                            "rule_id": "pr_7xk2m9c0d1",
                            "rule_name": "Finance to ERP"
                          }
                        }
                      ],
                      "blocked": [
                        {
                          "kind": "private_network",
                          "id": "pn_6b2x9q0wea",
                          "name": "Office LAN",
                          "rule": {
                            "rule_id": "pr_2m9x0k8d1s",
                            "rule_name": "Finance to office LAN"
                          },
                          "missing_posture": [
                            "pp_3k8x0s2m1d"
                          ],
                          "needs_trusted_device": false,
                          "person_suspended": false
                        }
                      ]
                    }
                  ],
                  "portal": {
                    "tiles": [
                      {
                        "id": "pa_4k8x2m0s9d",
                        "name": "Finance ERP",
                        "granted_by": {
                          "rule_id": "pr_7xk2m9c0d1",
                          "rule_name": "Finance to ERP"
                        }
                      }
                    ],
                    "hidden": [
                      {
                        "id": "pa_9d2k0s8x1m",
                        "name": "File server",
                        "reason": "browser access (clientless) is off for this app",
                        "locked": {
                          "reason": "browser-off",
                          "requires": []
                        }
                      }
                    ]
                  },
                  "evaluated_at": "2026-10-13T09:24:11.000Z"
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`person-not-found`: No person with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "person-not-found": {
                    "summary": "No person with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/person-not-found",
                      "code": "person-not-found",
                      "title": "person not found",
                      "status": 404,
                      "detail": "No person with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/people/{person_id}/groups": {
      "patch": {
        "tags": [
          "People"
        ],
        "operationId": "updatePersonGroups",
        "summary": "Change group membership",
        "description": "Adds the person to and removes them from groups without sending the whole list. Their devices' access is recalculated at once. Group ids are not checked against existing groups. Active Directory groups take their members from Active Directory and cannot be changed here. Audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "person_id",
            "in": "path",
            "required": true,
            "description": "Person id (from List people).",
            "schema": {
              "type": "string"
            },
            "example": "pz81kd03mna"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "add": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Group ids to add."
                  },
                  "remove": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Group ids to remove."
                  }
                },
                "description": "At least one of `add` / `remove` must be non-empty. A person can be in up to 200 groups."
              },
              "example": {
                "add": [
                  "g3k9d0s7aa"
                ],
                "remove": [
                  "g8s2k0d9xm"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The person with the new groups.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Person"
                },
                "example": {
                  "id": "pz81kd03mna",
                  "email": "dana.levi@example.com",
                  "name": "Dana Levi",
                  "groups": [
                    "g3k9d0s7aa"
                  ],
                  "created_by_integrator": null,
                  "idp": "cloudraw",
                  "mfa": false,
                  "suspended": false,
                  "quarantined": false,
                  "quarantined_at": null,
                  "quarantine_reason": null,
                  "created_at": "2026-09-20T07:41:02.000Z",
                  "last_seen": "2026-10-13T09:24:11.000Z",
                  "last_seen_via": "DANA-LAPTOP",
                  "device_count": 1,
                  "state": "active",
                  "invited_at": "2026-09-20T07:41:10.000Z",
                  "invite_count": 1,
                  "ad_groups_synced_at": null,
                  "files_security": null,
                  "via": null,
                  "requested_at": null,
                  "join_link_id": null,
                  "sign_in": {
                    "method": "cloudraw",
                    "second_factor": "email_code",
                    "method_source": "linked"
                  },
                  "idp_links": [],
                  "idp_links_checked_at": null,
                  "sign_in_conflict": null,
                  "phone_masked": null,
                  "sms_codes": false,
                  "second_factors": [
                    "email_code"
                  ],
                  "second_factors_checked_at": "2026-10-12T18:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "`add-or-remove-required`: Both `add` and `remove` are empty or missing.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "add-or-remove-required": {
                    "summary": "Both `add` and `remove` are empty or missing.",
                    "value": {
                      "type": "https://cloudraw.com/problems/add-or-remove-required",
                      "code": "add-or-remove-required",
                      "title": "add or remove required",
                      "status": 400,
                      "detail": "Both add and remove are empty or missing."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`person-not-found`: No person with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "person-not-found": {
                    "summary": "No person with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/person-not-found",
                      "code": "person-not-found",
                      "title": "person not found",
                      "status": 404,
                      "detail": "No person with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`group-managed-elsewhere`: One of the groups is an Active Directory group.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "group-managed-elsewhere": {
                    "summary": "One of the groups is an Active Directory group.",
                    "value": {
                      "type": "https://cloudraw.com/problems/group-managed-elsewhere",
                      "code": "group-managed-elsewhere",
                      "title": "group managed elsewhere",
                      "status": 409,
                      "detail": "One of the groups is an Active Directory group."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/people/{person_id}/invite": {
      "post": {
        "tags": [
          "People"
        ],
        "operationId": "invitePerson",
        "summary": "Invite a person",
        "description": "Sends (or re-sends) the sign-in invitation. Cloudraw creates the person's sign-in account if needed (or reuses the one with their e-mail), sets an e-mail code as their second step, and e-mails a branded \"set your password\" link together with the Cloudraw Connect download. A re-invite also lifts a sign-in lockout. Not available when the workspace signs in with its own identity provider: people then use their existing account. Audited.\n\n**Token:** full access · **Created by:** owner\n\n**Rate limit:** One invitation per person per minute.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "person_id",
            "in": "path",
            "required": true,
            "description": "Person id (from List people).",
            "schema": {
              "type": "string"
            },
            "example": "pz81kd03mna"
          }
        ],
        "responses": {
          "202": {
            "description": "The invitation was sent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonInvitation"
                },
                "example": {
                  "person_id": "p4hd8s0qk2l",
                  "email": "omer.katz@example.com",
                  "state": "invited",
                  "invited_at": "2026-10-13T09:24:11.000Z",
                  "invite_count": 1,
                  "sign_in": {
                    "method": "cloudraw",
                    "second_factor": "email_code"
                  }
                }
              }
            }
          },
          "400": {
            "description": "`email-required`: The person has no valid e-mail address.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "email-required": {
                    "summary": "The person has no valid e-mail address.",
                    "value": {
                      "type": "https://cloudraw.com/problems/email-required",
                      "code": "email-required",
                      "title": "email required",
                      "status": 400,
                      "detail": "The person has no valid e-mail address."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`person-not-found`: No person with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "person-not-found": {
                    "summary": "No person with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/person-not-found",
                      "code": "person-not-found",
                      "title": "person not found",
                      "status": 404,
                      "detail": "No person with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`person-suspended`: The person is suspended; un-suspend them first.\n\n`federated-sign-in`: The workspace signs in with its own identity provider; no invitation is needed.\n\n`sign-in-conflict`: Several sign-in accounts in the workspace use this e-mail address; remove the extra one first. Nothing was sent.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "person-suspended": {
                    "summary": "The person is suspended; un-suspend them first.",
                    "value": {
                      "type": "https://cloudraw.com/problems/person-suspended",
                      "code": "person-suspended",
                      "title": "person suspended",
                      "status": 409,
                      "detail": "The person is suspended; un-suspend them first."
                    }
                  },
                  "federated-sign-in": {
                    "summary": "The workspace signs in with its own identity provider; no invitation is needed.",
                    "value": {
                      "type": "https://cloudraw.com/problems/federated-sign-in",
                      "code": "federated-sign-in",
                      "title": "federated sign in",
                      "status": 409,
                      "detail": "The workspace signs in with its own identity provider; no invitation is needed."
                    }
                  },
                  "sign-in-conflict": {
                    "summary": "Several sign-in accounts in the workspace use this e-mail address; remove the extra one first. Nothing was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/sign-in-conflict",
                      "code": "sign-in-conflict",
                      "title": "sign in conflict",
                      "status": 409,
                      "detail": "Several sign-in accounts in the workspace use this e-mail address; remove the extra one first. Nothing was sent."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`invite-rate-limited`: An invitation was sent to this person less than a minute ago. Wait `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invite-rate-limited": {
                    "summary": "An invitation was sent to this person less than a minute ago. Wait `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invite-rate-limited",
                      "code": "invite-rate-limited",
                      "title": "invite rate limited",
                      "status": 429,
                      "detail": "An invitation was sent to this person less than a minute ago. Wait Retry-After seconds."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`invite-failed`: The invitation could not be sent right now; nothing was changed. Retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invite-failed": {
                    "summary": "The invitation could not be sent right now; nothing was changed. Retry.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invite-failed",
                      "code": "invite-failed",
                      "title": "invite failed",
                      "status": 502,
                      "detail": "The invitation could not be sent right now; nothing was changed. Retry."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`sso-not-configured`: Sign-in is not available on the platform right now.\n\n`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "sso-not-configured": {
                    "summary": "Sign-in is not available on the platform right now.",
                    "value": {
                      "type": "https://cloudraw.com/problems/sso-not-configured",
                      "code": "sso-not-configured",
                      "title": "sso not configured",
                      "status": 503,
                      "detail": "Sign-in is not available on the platform right now."
                    }
                  },
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        },
        "x-cloudraw-rate-limit": "One invitation per person per minute."
      }
    },
    "/v0/tenants/{tenant_id}/people/{person_id}/portal-signout": {
      "post": {
        "tags": [
          "People"
        ],
        "operationId": "signOutPersonFromPortal",
        "summary": "Sign a person out of the browser portal",
        "description": "Ends the person's browser portal sign-ins everywhere and cuts their open browser app sessions. They can sign in again right away; to keep them out, suspend or quarantine them instead. Device (Cloudraw Connect) sessions are not affected. Audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "person_id",
            "in": "path",
            "required": true,
            "description": "Person id (from List people).",
            "schema": {
              "type": "string"
            },
            "example": "pz81kd03mna"
          }
        ],
        "responses": {
          "200": {
            "description": "What was ended.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalSignout"
                },
                "example": {
                  "person_id": "pz81kd03mna",
                  "portal_sessions_ended": 1,
                  "browser_sessions_cut": 1,
                  "overlay": "ok"
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`person-not-found`: No person with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "person-not-found": {
                    "summary": "No person with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/person-not-found",
                      "code": "person-not-found",
                      "title": "person not found",
                      "status": 404,
                      "detail": "No person with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/people/{person_id}/quarantine": {
      "post": {
        "tags": [
          "People"
        ],
        "operationId": "quarantinePerson",
        "summary": "Quarantine a person",
        "description": "Puts the person under a security hold: they are suspended, every device and browser session is cut, portal sign-ins end and temporary access is revoked, until you release them. Unlike a plain suspension it records when and why, and raises a security alert in the workspace. Calling it again on a quarantined person updates the time and reason. Audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "person_id",
            "in": "path",
            "required": true,
            "description": "Person id (from List people).",
            "schema": {
              "type": "string"
            },
            "example": "pz81kd03mna"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string",
                    "description": "Why; shown in the console and the alert. Up to 300 characters are kept."
                  }
                }
              },
              "example": {
                "reason": "Credentials reported as phished"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The quarantined person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonQuarantined"
                },
                "example": {
                  "id": "pz81kd03mna",
                  "email": "dana.levi@example.com",
                  "name": "Dana Levi",
                  "groups": [
                    "g3k9d0s7aa"
                  ],
                  "created_by_integrator": null,
                  "idp": "cloudraw",
                  "mfa": false,
                  "suspended": true,
                  "quarantined": true,
                  "quarantined_at": "2026-10-13T09:24:11.000Z",
                  "quarantine_reason": "Credentials reported as phished",
                  "created_at": "2026-09-20T07:41:02.000Z",
                  "last_seen": "2026-10-13T09:24:11.000Z",
                  "last_seen_via": "DANA-LAPTOP",
                  "device_count": 1,
                  "state": "suspended",
                  "invited_at": "2026-09-20T07:41:10.000Z",
                  "invite_count": 1,
                  "ad_groups_synced_at": null,
                  "files_security": null,
                  "via": null,
                  "requested_at": null,
                  "join_link_id": null,
                  "sign_in": {
                    "method": "cloudraw",
                    "second_factor": "email_code",
                    "method_source": "linked"
                  },
                  "idp_links": [],
                  "idp_links_checked_at": null,
                  "sign_in_conflict": null,
                  "phone_masked": null,
                  "sms_codes": false,
                  "second_factors": [
                    "email_code"
                  ],
                  "second_factors_checked_at": "2026-10-12T18:00:00.000Z",
                  "sessions_cut": 3
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`person-not-found`: No person with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "person-not-found": {
                    "summary": "No person with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/person-not-found",
                      "code": "person-not-found",
                      "title": "person not found",
                      "status": 404,
                      "detail": "No person with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      },
      "delete": {
        "tags": [
          "People"
        ],
        "operationId": "releasePersonQuarantine",
        "summary": "Release a person from quarantine",
        "description": "Ends the security hold and restores the person's access through their groups. Note: releasing also clears the suspension, even if the person was suspended before the quarantine. Audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "person_id",
            "in": "path",
            "required": true,
            "description": "Person id (from List people).",
            "schema": {
              "type": "string"
            },
            "example": "pz81kd03mna"
          }
        ],
        "responses": {
          "200": {
            "description": "The released person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Person"
                },
                "example": {
                  "id": "pz81kd03mna",
                  "email": "dana.levi@example.com",
                  "name": "Dana Levi",
                  "groups": [
                    "g3k9d0s7aa"
                  ],
                  "created_by_integrator": null,
                  "idp": "cloudraw",
                  "mfa": false,
                  "suspended": false,
                  "quarantined": false,
                  "quarantined_at": null,
                  "quarantine_reason": null,
                  "created_at": "2026-09-20T07:41:02.000Z",
                  "last_seen": "2026-10-13T09:24:11.000Z",
                  "last_seen_via": "DANA-LAPTOP",
                  "device_count": 1,
                  "state": "active",
                  "invited_at": "2026-09-20T07:41:10.000Z",
                  "invite_count": 1,
                  "ad_groups_synced_at": null,
                  "files_security": null,
                  "via": null,
                  "requested_at": null,
                  "join_link_id": null,
                  "sign_in": {
                    "method": "cloudraw",
                    "second_factor": "email_code",
                    "method_source": "linked"
                  },
                  "idp_links": [],
                  "idp_links_checked_at": null,
                  "sign_in_conflict": null,
                  "phone_masked": null,
                  "sms_codes": false,
                  "second_factors": [
                    "email_code"
                  ],
                  "second_factors_checked_at": "2026-10-12T18:00:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`person-not-found`: No person with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "person-not-found": {
                    "summary": "No person with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/person-not-found",
                      "code": "person-not-found",
                      "title": "person not found",
                      "status": 404,
                      "detail": "No person with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`person-not-quarantined`: The person is not quarantined.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "person-not-quarantined": {
                    "summary": "The person is not quarantined.",
                    "value": {
                      "type": "https://cloudraw.com/problems/person-not-quarantined",
                      "code": "person-not-quarantined",
                      "title": "person not quarantined",
                      "status": 409,
                      "detail": "The person is not quarantined."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/people/{person_id}/unlock": {
      "post": {
        "tags": [
          "People"
        ],
        "operationId": "unlockPerson",
        "summary": "Unlock a person's sign-in",
        "description": "Lifts a sign-in lockout (too many wrong codes or passwords) without sending a new invitation. Only for people with a Cloudraw sign-in account; people who sign in through your directory or identity provider are unlocked there. Audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "person_id",
            "in": "path",
            "required": true,
            "description": "Person id (from List people).",
            "schema": {
              "type": "string"
            },
            "example": "pz81kd03mna"
          }
        ],
        "responses": {
          "200": {
            "description": "Unlocked.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonUnlock"
                },
                "example": {
                  "id": "pz81kd03mna",
                  "unlocked": true,
                  "was_locked": true
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`person-not-found`: No person with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "person-not-found": {
                    "summary": "No person with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/person-not-found",
                      "code": "person-not-found",
                      "title": "person not found",
                      "status": 404,
                      "detail": "No person with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`no-cloudraw-sign-in`: The person has no Cloudraw sign-in account (they sign in with your directory or identity provider).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "no-cloudraw-sign-in": {
                    "summary": "The person has no Cloudraw sign-in account (they sign in with your directory or identity provider).",
                    "value": {
                      "type": "https://cloudraw.com/problems/no-cloudraw-sign-in",
                      "code": "no-cloudraw-sign-in",
                      "title": "no cloudraw sign in",
                      "status": 409,
                      "detail": "The person has no Cloudraw sign-in account (they sign in with your directory or identity provider)."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`unlock-failed`: The sign-in service could not unlock the account right now. Retry in a minute.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unlock-failed": {
                    "summary": "The sign-in service could not unlock the account right now. Retry in a minute.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unlock-failed",
                      "code": "unlock-failed",
                      "title": "unlock failed",
                      "status": 502,
                      "detail": "The sign-in service could not unlock the account right now. Retry in a minute."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/policy-rule-catalog": {
      "get": {
        "tags": [
          "Access rules"
        ],
        "operationId": "getConditionCatalog",
        "summary": "Get the condition catalog",
        "description": "Lists every condition type, field and operator that access and trust rules accept, the allowed values (OS families, second-step methods, …) and notes on what is enforced. The catalog is the same for every workspace; it carries an `ETag`, so send `If-None-Match` to get `304 Not Modified` when it has not changed.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "responses": {
          "200": {
            "description": "The catalog.",
            "headers": {
              "ETag": {
                "description": "Catalog version.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConditionCatalog"
                },
                "example": {
                  "generated_at": "2026-10-06T00:00:00Z",
                  "types": [
                    {
                      "type": "group",
                      "value_type": "group_ref",
                      "operators": [
                        {
                          "operator": "in",
                          "arity": "list",
                          "value_type": "group_id_list",
                          "note": "value = [immutable group id, …] (directory, SCIM or local groups)"
                        }
                      ]
                    },
                    {
                      "type": "posture",
                      "value_type": null,
                      "fields": [
                        {
                          "field": "disk_encrypted",
                          "operators": [
                            "eq"
                          ],
                          "value_type": "bool",
                          "note": "OS volume encrypted (BitLocker on)"
                        }
                      ],
                      "operators": [
                        {
                          "operator": "eq",
                          "arity": "scalar",
                          "value_type": "bool"
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "304": {
            "description": "`If-None-Match` matches the current catalog."
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/policy-rules": {
      "get": {
        "tags": [
          "Access rules"
        ],
        "operationId": "listPolicyRules",
        "summary": "List access rules",
        "description": "Returns the access rules in the workspace, oldest first, with whether each is live at the edge (`enforced`) and why not. Cloudraw is deny-by-default: an app is reachable only through an enforced `allow` rule. Pass `limit` to page: `next_cursor` is non-null while more rules follow; pass it back as `cursor` to get the next page. Without `limit` every rule comes back in one answer.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "effect",
            "in": "query",
            "required": false,
            "description": "Only rules with this effect.",
            "schema": {
              "type": "string",
              "enum": [
                "allow",
                "deny"
              ]
            },
            "example": "allow"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size, 1-200 (above 200 = 200). Leave it out to get every rule in one answer.",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 50
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "The `next_cursor` of the previous page, unchanged.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Access rules (one page when `limit` is set).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PolicyRule"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Opaque cursor for the next page; null on the last page."
                    }
                  },
                  "required": [
                    "items"
                  ]
                },
                "example": {
                  "items": [
                    {
                      "id": "pr_7xk2m9c0d1",
                      "name": "Finance → ERP from encrypted laptops",
                      "effect": "allow",
                      "target": {
                        "service_id": "cx9m2v7d1pa"
                      },
                      "match": {
                        "op": "and",
                        "children": [
                          {
                            "op": "or",
                            "children": [
                              {
                                "type": "group",
                                "operator": "in",
                                "value": [
                                  "g3k9d0s7aa"
                                ]
                              },
                              {
                                "type": "person",
                                "operator": "in",
                                "value": [
                                  "p4hd8s0qk2l"
                                ]
                              }
                            ]
                          },
                          {
                            "type": "posture",
                            "field": "disk_encrypted",
                            "operator": "eq",
                            "value": true
                          }
                        ]
                      },
                      "enforced": true,
                      "enforcement_reason": null,
                      "enforcement_status": "active_at_edge",
                      "traffic_effect": "Allowed for the groups, people or devices it names — live at the edge now.",
                      "form_representable": true,
                      "form_view": {
                        "include": [
                          {
                            "type": "group",
                            "operator": "in",
                            "value": [
                              "g3k9d0s7aa"
                            ],
                            "resolved_groups": [
                              {
                                "id": "g3k9d0s7aa",
                                "display_name": "Finance",
                                "state": "active"
                              }
                            ]
                          },
                          {
                            "type": "person",
                            "operator": "in",
                            "value": [
                              "p4hd8s0qk2l"
                            ],
                            "resolved_people": [
                              {
                                "id": "p4hd8s0qk2l",
                                "display_name": "Omer Katz",
                                "email": "omer.katz@example.com",
                                "state": "active"
                              }
                            ]
                          }
                        ],
                        "require": [
                          {
                            "type": "posture",
                            "field": "disk_encrypted",
                            "operator": "eq",
                            "value": true
                          }
                        ],
                        "exclude": []
                      },
                      "version": 3,
                      "created_at": "2026-10-02T07:41:09.000Z",
                      "updated_at": "2026-10-13T09:24:11.000Z"
                    },
                    {
                      "id": "pr_2d8s0k9x1m",
                      "name": "Contractors → ERP office hours",
                      "effect": "allow",
                      "target": {
                        "service_id": "cx9m2v7d1pa"
                      },
                      "match": {
                        "op": "and",
                        "children": [
                          {
                            "type": "group",
                            "operator": "in",
                            "value": [
                              "g3k9d0s7aa"
                            ]
                          },
                          {
                            "type": "time",
                            "operator": "within",
                            "value": {
                              "tz": "Asia/Jerusalem",
                              "start": "08:00",
                              "end": "18:00"
                            }
                          }
                        ]
                      },
                      "enforced": false,
                      "enforcement_reason": "condition \"time/within\" is not yet enforceable at the overlay; left deny to avoid over-permitting",
                      "enforcement_status": "not_at_edge",
                      "traffic_effect": "DENIED right now — this rule cannot be applied at the edge yet, so it grants NO access. condition \"time/within\" is not yet enforceable at the overlay; left deny to avoid over-permitting",
                      "form_representable": true,
                      "form_view": {
                        "include": [
                          {
                            "type": "group",
                            "operator": "in",
                            "value": [
                              "g3k9d0s7aa"
                            ],
                            "resolved_groups": [
                              {
                                "id": "g3k9d0s7aa",
                                "display_name": "Contractors",
                                "state": "active"
                              }
                            ]
                          }
                        ],
                        "require": [
                          {
                            "type": "time",
                            "operator": "within",
                            "value": {
                              "tz": "Asia/Jerusalem",
                              "start": "08:00",
                              "end": "18:00"
                            }
                          }
                        ],
                        "exclude": []
                      },
                      "version": 1,
                      "created_at": "2026-10-09T12:00:00.000Z",
                      "updated_at": "2026-10-09T12:00:00.000Z"
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "description": "`invalid-limit`: `limit` is not a whole number of at least 1.\n\n`invalid-cursor`: `cursor` is not a `next_cursor` from this list.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-limit": {
                    "summary": "`limit` is not a whole number of at least 1.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-limit",
                      "code": "invalid-limit",
                      "title": "invalid limit",
                      "status": 400,
                      "detail": "limit is not a whole number of at least 1."
                    }
                  },
                  "invalid-cursor": {
                    "summary": "`cursor` is not a `next_cursor` from this list.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-cursor",
                      "code": "invalid-cursor",
                      "title": "invalid cursor",
                      "status": 400,
                      "detail": "cursor is not a next_cursor from this list."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      },
      "post": {
        "tags": [
          "Access rules"
        ],
        "operationId": "createPolicyRule",
        "summary": "Create an access rule",
        "description": "Creates an access rule and applies it at the edge immediately; the answer tells you whether it is live (`enforced`). A rule Cloudraw cannot enforce exactly as written is saved but grants nothing, so it never allows more than you wrote. Deny wins: a `deny` rule removes access, at the edge, from the people and devices it matches, whatever allow rule, group or temporary access would let them in. Apart from that there is no rule priority: a device reaches an app when an enforced allow rule grants it and no deny rule matches it. Use **Preview a change** first to see who gains and who loses access. Audited. A change that gives access (an allow turned on, any condition / target edit of an enabled rule, a deny turned off or made an allow) is made in the Cloudraw console: API tokens get `403 widening-console-only`.\n\n**Token:** full access · **Created by:** owner\n\n**Idempotency:** send `Idempotency-Key` to retry safely — the same key and body within 24 h returns the first answer.\n\n### Conditions (`match`)\n\nA condition tree. Every node is either a **group node** or a **leaf**.\n\n**Group node** — `{ \"op\": \"and\" | \"or\", \"children\": [ …nodes ], \"negate\"?: true }`. `and` = all children must hold, `or` = at least one.\n`negate: true` on an `or` node marks an *exclude* list (shown as \"Except\" in the console).\n\n**Leaf** — `{ \"type\", \"field\"?, \"operator\", \"value\" }`:\n\n| type | field | operator | value |\n|---|---|---|---|\n| `group` | – | `in`, `not_in` | group ids (from the Groups API) |\n| `person` | – | `in` | 1-200 person ids |\n| `device` | – | `in` | 1-200 device ids |\n| `email` | – | `in` | 1-200 e-mail addresses (deny rules only: a person's, or a vendor's on a temporary-access grant) |\n| `jit_grant` | – | `in` | 1-200 temporary-access grant ids (deny rules only) |\n| `posture` | `managed`, `domain_joined`, `workgroup`, `entra_joined`, `mdm_enrolled`, `disk_encrypted`, `antivirus_on`, `antivirus_present`, `edr_present`, `firewall_on`, `os_up_to_date`, `screen_lock` | `eq` | `true` or `false` |\n| `posture` | `computer_type` | `in` | non-empty subset of `[\"domain\",\"workgroup\"]` |\n| `posture` | `os_in` | `in` | 1-20 OS family ids: `windows`, `macos`, `linux`, `android`, `ios` |\n| `network` | `country` | `in`, `not_in` | ISO 3166 alpha-2 codes, e.g. `[\"IL\",\"NL\"]` |\n| `network` | `ip` | `in`, `not_in` | IP addresses or CIDRs |\n| `network` | `asn` | `in`, `not_in` | integers |\n| `network` | `risk` | `eq` / `in` | `vpn`, `tor`, `hosting`, `anonymizer`, `proxy` (one / a list) |\n| `time` | – | `within` | `{ \"tz\": \"<IANA zone>\", \"start\": \"HH:MM\", \"end\": \"HH:MM\" }` |\n| `time` | – | `day_in` | subset of `mon`…`sun` |\n| `mfa` | `satisfied` / `method_in` / `max_age_seconds` | same as field | boolean / method ids / 60-2592000 |\n| `app` | – | `publisher_eq` / `hash_in` / `signed` | string / non-empty list / boolean |\n| `attribute` | attribute name | `eq`, `ne`, `contains`, `starts_with`, `ends_with`, `regex`, `in`, `not_in`, `gt`, `gte`, `lt`, `lte`, `between` | scalar / list / number / `{from,to}`; `regex` ≤ 512 characters, linear-time only |\n\nGet the full, machine-readable list (with labels) from **Get the condition catalog**.\n\n**What is actually enforced.** Every leaf above is validated and stored, but not every leaf is evaluated yet:\n- *Allow rules* are enforced only when they are built from `group in`, `person in`, `device in`, `posture` `eq true/false` / `computer_type` and `mfa` (`satisfied: true`, `method_in`, `max_age_seconds`) leaves, combined with `and` / `or` (no `negate`), with a group, person or device in every combination, and at most 16 combinations. Anything else is saved but grants **nothing** (`enforced: false`, with the reason in `enforcement_reason`). `mfa` leaves are judged on the device's last verified second step (its own Cloudraw Connect sign-in), never on an admin flag.\n- *Deny rules* win over every allow rule, group, direct grant and temporary (just-in-time) access of the people and devices they match. They must name one app (`service_id`), one private network (`private_network_id`) or every app (`service_role` `<tenant>-services`). They evaluate `group`, `person`, `device`, `posture`, `mfa` and `network` (`country`, `asn`, `risk`) leaves; an input that is unknown (no fresh health report, no location, a browser with no device) counts as **matching**. A deny with a `time`, `app`, `attribute` or `network ip` leaf is applied to everyone it could match (`enforcement_status: fail_closed`).\n- *Trust rules* evaluate `group`, `person`, `device`, `posture` (including `os_in`), `network` and `mfa` leaves. `time`, `app` and `attribute` leaves are never met yet.\n- Turn a rule off with `enabled: false` (it then has no effect) and on again with `enabled: true`. **Preview a change** shows who gains and who loses access before you save it.\n- A device health report older than 60 minutes counts as *not reported*: it matches neither `true` nor `false`.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "1-128 characters."
                  },
                  "effect": {
                    "type": "string",
                    "enum": [
                      "allow",
                      "deny"
                    ]
                  },
                  "enabled": {
                    "type": "boolean",
                    "description": "Default true. False saves the rule turned off."
                  },
                  "target": {
                    "$ref": "#/components/schemas/RuleTarget"
                  },
                  "match": {
                    "$ref": "#/components/schemas/ConditionNode"
                  }
                },
                "required": [
                  "name",
                  "effect",
                  "target",
                  "match"
                ]
              },
              "example": {
                "name": "Finance → ERP from encrypted laptops",
                "effect": "allow",
                "target": {
                  "service_id": "cx9m2v7d1pa"
                },
                "match": {
                  "op": "and",
                  "children": [
                    {
                      "op": "or",
                      "children": [
                        {
                          "type": "group",
                          "operator": "in",
                          "value": [
                            "g3k9d0s7aa"
                          ]
                        },
                        {
                          "type": "person",
                          "operator": "in",
                          "value": [
                            "p4hd8s0qk2l"
                          ]
                        }
                      ]
                    },
                    {
                      "type": "posture",
                      "field": "disk_encrypted",
                      "operator": "eq",
                      "value": true
                    }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The rule as stored, with its enforcement status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PolicyRule"
                },
                "example": {
                  "id": "pr_7xk2m9c0d1",
                  "name": "Finance → ERP from encrypted laptops",
                  "effect": "allow",
                  "target": {
                    "service_id": "cx9m2v7d1pa"
                  },
                  "match": {
                    "op": "and",
                    "children": [
                      {
                        "op": "or",
                        "children": [
                          {
                            "type": "group",
                            "operator": "in",
                            "value": [
                              "g3k9d0s7aa"
                            ]
                          },
                          {
                            "type": "person",
                            "operator": "in",
                            "value": [
                              "p4hd8s0qk2l"
                            ]
                          }
                        ]
                      },
                      {
                        "type": "posture",
                        "field": "disk_encrypted",
                        "operator": "eq",
                        "value": true
                      }
                    ]
                  },
                  "enforced": true,
                  "enforcement_reason": null,
                  "enforcement_status": "active_at_edge",
                  "traffic_effect": "Allowed for the groups, people or devices it names — live at the edge now.",
                  "form_representable": true,
                  "form_view": {
                    "include": [
                      {
                        "type": "group",
                        "operator": "in",
                        "value": [
                          "g3k9d0s7aa"
                        ],
                        "resolved_groups": [
                          {
                            "id": "g3k9d0s7aa",
                            "display_name": "Finance",
                            "state": "active"
                          }
                        ]
                      },
                      {
                        "type": "person",
                        "operator": "in",
                        "value": [
                          "p4hd8s0qk2l"
                        ],
                        "resolved_people": [
                          {
                            "id": "p4hd8s0qk2l",
                            "display_name": "Omer Katz",
                            "email": "omer.katz@example.com",
                            "state": "active"
                          }
                        ]
                      }
                    ],
                    "require": [
                      {
                        "type": "posture",
                        "field": "disk_encrypted",
                        "operator": "eq",
                        "value": true
                      }
                    ],
                    "exclude": []
                  },
                  "version": 1,
                  "created_at": "2026-10-02T07:41:09.000Z",
                  "updated_at": "2026-10-02T07:41:09.000Z"
                }
              }
            }
          },
          "400": {
            "description": "`invalid-policy-rule`: The body fails validation; `detail` lists every problem as `path: message` (e.g. `match.children[1].value: posture disk_encrypted needs operator eq + boolean value`, `target: exactly one of service_id, service_role or private_network_id`, `target.service_id: unknown app`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-policy-rule": {
                    "summary": "The body fails validation; `detail` lists every problem as `path: message` (e.g. `match.children[1].value: posture disk_encrypted needs operator eq + boolean value`, `target: exactly one of service_id, service_role or private_network_id`, `target.service_id: unknown app`).",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-policy-rule",
                      "code": "invalid-policy-rule",
                      "title": "invalid policy rule",
                      "status": 400,
                      "detail": "The body fails validation; detail lists every problem as path: message (e.g. match.children[1].value: posture disk_encrypted needs operator eq + boolean value, target: exactly one of service_id, service_role or private_network_id, target.service_id: unknown app)."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`widening-console-only`: This rule gives access: create it in the Cloudraw console.\n\n`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "widening-console-only": {
                    "summary": "This rule gives access: create it in the Cloudraw console.",
                    "value": {
                      "type": "https://cloudraw.com/problems/widening-console-only",
                      "code": "widening-console-only",
                      "title": "widening console only",
                      "status": 403,
                      "detail": "This rule gives access: create it in the Cloudraw console."
                    }
                  },
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`idempotency-key-reuse`: The same `Idempotency-Key` was used with a different body within 24 hours.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "idempotency-key-reuse": {
                    "summary": "The same `Idempotency-Key` was used with a different body within 24 hours.",
                    "value": {
                      "type": "https://cloudraw.com/problems/idempotency-key-reuse",
                      "code": "idempotency-key-reuse",
                      "title": "idempotency key reuse",
                      "status": 409,
                      "detail": "The same Idempotency-Key was used with a different body within 24 hours."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        },
        "x-cloudraw-idempotent": true
      }
    },
    "/v0/tenants/{tenant_id}/policy-rules:evaluate": {
      "post": {
        "tags": [
          "Access rules"
        ],
        "operationId": "evaluatePolicyRule",
        "summary": "Test a draft access rule",
        "description": "Validates a draft condition tree without saving anything. With a `target` it also tells you whether the draft, saved as an `allow` rule, would be enforced and which devices it would grant right now. Validation problems come back in `errors` with `compiles: false` (status 200), so you can show them next to the field.\n\n**Token:** read-only or full access · **Created by:** owner or security admin\n\n**Idempotency:** send `Idempotency-Key` to retry safely — the same key and body within 24 h returns the first answer.\n\nAn empty `match` comes back as `compiles: false` with `errors: [{path: \"match\", message: \"match required\"}]`.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "match": {
                    "$ref": "#/components/schemas/ConditionNode"
                  },
                  "target": {
                    "$ref": "#/components/schemas/RuleTarget"
                  }
                },
                "required": [
                  "match"
                ]
              },
              "example": {
                "match": {
                  "op": "and",
                  "children": [
                    {
                      "op": "or",
                      "children": [
                        {
                          "type": "group",
                          "operator": "in",
                          "value": [
                            "g3k9d0s7aa"
                          ]
                        },
                        {
                          "type": "person",
                          "operator": "in",
                          "value": [
                            "p4hd8s0qk2l"
                          ]
                        }
                      ]
                    },
                    {
                      "type": "posture",
                      "field": "disk_encrypted",
                      "operator": "eq",
                      "value": true
                    }
                  ]
                },
                "target": {
                  "service_id": "cx9m2v7d1pa"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The dry-run result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PolicyRuleEvaluation"
                },
                "example": {
                  "compiles": true,
                  "errors": [],
                  "enforced": true,
                  "enforcement_reason": null,
                  "match_count": 7,
                  "sample_matches": [
                    {
                      "device_id": "dvc_5mxq2b7r8k",
                      "device_name": "FIN-LT-014",
                      "person": "Dana Levi"
                    }
                  ],
                  "warnings": [],
                  "form_representable": true,
                  "form_view": {
                    "include": [
                      {
                        "type": "group",
                        "operator": "in",
                        "value": [
                          "g3k9d0s7aa"
                        ],
                        "resolved_groups": [
                          {
                            "id": "g3k9d0s7aa",
                            "display_name": "Finance",
                            "state": "active"
                          }
                        ]
                      },
                      {
                        "type": "person",
                        "operator": "in",
                        "value": [
                          "p4hd8s0qk2l"
                        ],
                        "resolved_people": [
                          {
                            "id": "p4hd8s0qk2l",
                            "display_name": "Omer Katz",
                            "email": "omer.katz@example.com",
                            "state": "active"
                          }
                        ]
                      }
                    ],
                    "require": [
                      {
                        "type": "posture",
                        "field": "disk_encrypted",
                        "operator": "eq",
                        "value": true
                      }
                    ],
                    "exclude": []
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`idempotency-key-reuse`: The same `Idempotency-Key` was used with a different body within 24 hours.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "idempotency-key-reuse": {
                    "summary": "The same `Idempotency-Key` was used with a different body within 24 hours.",
                    "value": {
                      "type": "https://cloudraw.com/problems/idempotency-key-reuse",
                      "code": "idempotency-key-reuse",
                      "title": "idempotency key reuse",
                      "status": 409,
                      "detail": "The same Idempotency-Key was used with a different body within 24 hours."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        },
        "x-cloudraw-idempotent": true
      }
    },
    "/v0/tenants/{tenant_id}/policy-rules:preview": {
      "post": {
        "tags": [
          "Access rules"
        ],
        "operationId": "previewPolicyRuleChange",
        "summary": "Preview a change",
        "description": "Shows exactly who GAINS and who LOSES access (people, their devices and the browser portal, per app) if you create, change, delete, turn off or turn on access rules — before you save. It runs the same evaluation the edge uses, on a copy: nothing is stored, nothing is applied, nothing is audited. Send one change (`op`, `rule_id`, `rule`) or several (`changes`, up to 25, applied in order). Each row says why (`why`, the last line of `trace`). `used_recently` marks a loss someone used in the last 7 days. At most 30 previews a minute per workspace. It lists people, so console admins need the owner, security_admin or auditor role.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "op": {
                    "type": "string",
                    "enum": [
                      "create",
                      "update",
                      "delete",
                      "enable",
                      "disable"
                    ]
                  },
                  "rule_id": {
                    "type": "string",
                    "description": "The rule to change (update / delete / enable / disable)."
                  },
                  "base_version": {
                    "type": "integer",
                    "description": "Optional: the rule version you are editing; a newer stored version is reported as an error."
                  },
                  "rule": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string",
                        "description": "1-128 characters."
                      },
                      "effect": {
                        "type": "string",
                        "enum": [
                          "allow",
                          "deny"
                        ]
                      },
                      "enabled": {
                        "type": "boolean",
                        "description": "On / off."
                      },
                      "target": {
                        "$ref": "#/components/schemas/RuleTarget"
                      },
                      "match": {
                        "$ref": "#/components/schemas/ConditionNode"
                      }
                    },
                    "description": "create: the whole rule; update: the fields that change."
                  },
                  "changes": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "op": {
                          "type": "string",
                          "enum": [
                            "create",
                            "update",
                            "delete",
                            "enable",
                            "disable"
                          ]
                        },
                        "rule_id": {
                          "type": "string",
                          "description": "Rule id."
                        },
                        "base_version": {
                          "type": "integer",
                          "description": "Rule version."
                        },
                        "rule": {
                          "type": "object",
                          "properties": {},
                          "description": "As above."
                        }
                      },
                      "required": [
                        "op"
                      ]
                    },
                    "description": "Several changes at once, instead of `op`."
                  },
                  "limit": {
                    "type": "integer",
                    "description": "Rows per list (gains / loses), 0-200. Default 20; the summary always counts everything."
                  }
                }
              },
              "example": {
                "op": "create",
                "rule": {
                  "name": "No ERP for contractors",
                  "effect": "deny",
                  "target": {
                    "service_id": "cx9m2v7d1pa"
                  },
                  "match": {
                    "type": "group",
                    "operator": "in",
                    "value": [
                      "g3k9d0s7aa"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Who gains and who loses access.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "read_only": {
                      "type": "boolean",
                      "description": "Always true."
                    },
                    "summary": {
                      "type": "object",
                      "properties": {
                        "gains": {
                          "type": "integer",
                          "description": "Rows that gain."
                        },
                        "loses": {
                          "type": "integer",
                          "description": "Rows that lose."
                        },
                        "people_gaining": {
                          "type": "integer",
                          "description": "People."
                        },
                        "people_losing": {
                          "type": "integer",
                          "description": "People."
                        },
                        "devices_gaining": {
                          "type": "integer",
                          "description": "Devices."
                        },
                        "devices_losing": {
                          "type": "integer",
                          "description": "Devices."
                        },
                        "apps_gaining": {
                          "type": "integer",
                          "description": "Apps."
                        },
                        "apps_losing": {
                          "type": "integer",
                          "description": "Apps."
                        },
                        "unchanged": {
                          "type": "integer",
                          "description": "Rows that stay the same."
                        },
                        "sessions_cut": {
                          "type": [
                            "integer",
                            "null"
                          ],
                          "description": "Live sessions that would end (null when the overlay can't be read)."
                        },
                        "used_recently": {
                          "type": "integer",
                          "description": "Losses used in the last 7 days."
                        },
                        "apps_exposed_to_everyone": {
                          "type": "integer",
                          "description": "Apps every person could open afterwards."
                        }
                      }
                    },
                    "gains": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "person": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Person id."
                              },
                              "name": {
                                "type": "string",
                                "description": "Name."
                              }
                            }
                          },
                          "device": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Device id, or \"browser\" for the portal."
                              },
                              "name": {
                                "type": "string",
                                "description": "Name."
                              }
                            }
                          },
                          "app": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "App or private network id."
                              },
                              "name": {
                                "type": "string",
                                "description": "Name."
                              },
                              "kind": {
                                "type": "string",
                                "enum": [
                                  "connection",
                                  "private_network"
                                ]
                              }
                            }
                          },
                          "before": {
                            "type": "object",
                            "properties": {
                              "allowed": {
                                "type": "boolean",
                                "description": "Before."
                              },
                              "rules": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "id": {
                                      "type": "string",
                                      "description": "Rule id."
                                    },
                                    "name": {
                                      "type": "string",
                                      "description": "Rule name."
                                    }
                                  }
                                }
                              }
                            }
                          },
                          "after": {
                            "type": "object",
                            "properties": {
                              "allowed": {
                                "type": "boolean",
                                "description": "After."
                              },
                              "rules": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "id": {
                                      "type": "string",
                                      "description": "Rule id."
                                    },
                                    "name": {
                                      "type": "string",
                                      "description": "Rule name."
                                    }
                                  }
                                }
                              }
                            }
                          },
                          "used_recently": {
                            "type": "boolean",
                            "description": "Losses only."
                          },
                          "why": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "One line: why."
                          },
                          "trace": {
                            "type": "array",
                            "items": {
                              "type": "string",
                              "description": "Step."
                            },
                            "description": "The decision, step by step."
                          }
                        }
                      },
                      "description": "Up to `limit` rows."
                    },
                    "loses": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {},
                        "description": "Same shape as gains."
                      },
                      "description": "Up to `limit` rows."
                    },
                    "truncated": {
                      "type": "boolean",
                      "description": "More rows than `limit`."
                    },
                    "changes": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "op": {
                            "type": "string",
                            "description": "The change."
                          },
                          "rule_id": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Rule id."
                          },
                          "sentence": {
                            "type": "string",
                            "description": "The rule in one sentence."
                          },
                          "enforcement": {
                            "type": "object",
                            "properties": {
                              "enforced": {
                                "type": "boolean",
                                "description": "Would be live at the edge."
                              },
                              "reason": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Why not."
                              },
                              "fail_closed": {
                                "type": "boolean",
                                "description": "Deny only: applied to everyone it could match."
                              }
                            }
                          }
                        }
                      },
                      "description": "Each change, with its edge status."
                    },
                    "warnings": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "description": "Warning."
                      }
                    },
                    "evaluated_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                },
                "example": {
                  "read_only": true,
                  "summary": {
                    "gains": 0,
                    "loses": 2,
                    "people_gaining": 0,
                    "people_losing": 2,
                    "devices_gaining": 0,
                    "devices_losing": 2,
                    "apps_gaining": 0,
                    "apps_losing": 1,
                    "unchanged": 14,
                    "sessions_cut": 0,
                    "used_recently": 1,
                    "apps_exposed_to_everyone": 0
                  },
                  "gains": [],
                  "loses": [
                    {
                      "person": {
                        "id": "p4hd8s0qk2l",
                        "name": "Omer Katz"
                      },
                      "device": {
                        "id": "dvc_5mxq2b7r8k",
                        "name": "FIN-LT-014"
                      },
                      "app": {
                        "id": "cx9m2v7d1pa",
                        "name": "erp-db",
                        "kind": "connection"
                      },
                      "before": {
                        "allowed": true,
                        "rules": [
                          {
                            "id": "pr_7xk2m9c0d1",
                            "name": "Finance → ERP from encrypted laptops"
                          }
                        ]
                      },
                      "after": {
                        "allowed": false,
                        "rules": []
                      },
                      "used_recently": true,
                      "why": "Result: BLOCKED — the device passes the trust gate, but no rule grants it (see the rule lines above).",
                      "trace": [
                        "Rule \"No ERP for contractors\" is a deny rule and it matches this device: it blocks \"erp-db\" whatever allow rule, group or temporary access applies (deny wins)."
                      ]
                    }
                  ],
                  "truncated": false,
                  "changes": [
                    {
                      "op": "create",
                      "rule_id": null,
                      "sentence": "Contractors cannot open erp-db.",
                      "enforcement": {
                        "enforced": true,
                        "reason": null
                      }
                    }
                  ],
                  "warnings": [],
                  "evaluated_at": "2026-10-13T09:24:11.000Z"
                }
              }
            }
          },
          "400": {
            "description": "`invalid-preview`: The changes fail validation (`errors` lists `path: message`): unknown op, unknown rule (also another workspace's rule), bad rule body, `limit` outside 0-200.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-preview": {
                    "summary": "The changes fail validation (`errors` lists `path: message`): unknown op, unknown rule (also another workspace's rule), bad rule body, `limit` outside 0-200.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-preview",
                      "code": "invalid-preview",
                      "title": "invalid preview",
                      "status": 400,
                      "detail": "The changes fail validation (errors lists path: message): unknown op, unknown rule (also another workspace's rule), bad rule body, limit outside 0-200."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`too-many-previews`: More than 30 previews a minute in this workspace; `Retry-After` says when to try again.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "too-many-previews": {
                    "summary": "More than 30 previews a minute in this workspace; `Retry-After` says when to try again.",
                    "value": {
                      "type": "https://cloudraw.com/problems/too-many-previews",
                      "code": "too-many-previews",
                      "title": "too many previews",
                      "status": 429,
                      "detail": "More than 30 previews a minute in this workspace; Retry-After says when to try again."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/policy-rules/{rule_id}": {
      "patch": {
        "tags": [
          "Access rules"
        ],
        "operationId": "updatePolicyRule",
        "summary": "Update an access rule",
        "description": "Changes any of `name`, `effect`, `enabled`, `target` and `match` (a field you leave out keeps its value; `match` is replaced as a whole). `enabled: false` turns the rule off, `true` turns it on again. The rule is re-applied at the edge immediately and the answer shows the new enforcement status. Requires `If-Match`. Audited. A change that gives access (an allow turned on, any condition / target edit of an enabled rule, a deny turned off or made an allow) is made in the Cloudraw console: API tokens get `403 widening-console-only`.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "rule_id",
            "in": "path",
            "required": true,
            "description": "Access rule id (from List access rules).",
            "schema": {
              "type": "string"
            },
            "example": "pr_7xk2m9c0d1"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "description": "The rule's current `version` (from a GET or the last write). Required: without it the call answers `428 if-match-required`; with a stale value `409 version-conflict`.",
            "schema": {
              "type": "string"
            },
            "example": "3"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "1-128 characters."
                  },
                  "effect": {
                    "type": "string",
                    "enum": [
                      "allow",
                      "deny"
                    ]
                  },
                  "enabled": {
                    "type": "boolean",
                    "description": "Turn the rule off (false) or on (true)."
                  },
                  "target": {
                    "$ref": "#/components/schemas/RuleTarget"
                  },
                  "match": {
                    "$ref": "#/components/schemas/ConditionNode"
                  }
                }
              },
              "example": {
                "match": {
                  "op": "and",
                  "children": [
                    {
                      "op": "or",
                      "children": [
                        {
                          "type": "group",
                          "operator": "in",
                          "value": [
                            "g3k9d0s7aa"
                          ]
                        },
                        {
                          "type": "person",
                          "operator": "in",
                          "value": [
                            "p4hd8s0qk2l"
                          ]
                        }
                      ]
                    },
                    {
                      "type": "posture",
                      "field": "disk_encrypted",
                      "operator": "eq",
                      "value": true
                    },
                    {
                      "type": "posture",
                      "field": "edr_present",
                      "operator": "eq",
                      "value": true
                    }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated rule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PolicyRule"
                },
                "example": {
                  "id": "pr_7xk2m9c0d1",
                  "name": "Finance → ERP from encrypted laptops",
                  "effect": "allow",
                  "target": {
                    "service_id": "cx9m2v7d1pa"
                  },
                  "match": {
                    "op": "and",
                    "children": [
                      {
                        "op": "or",
                        "children": [
                          {
                            "type": "group",
                            "operator": "in",
                            "value": [
                              "g3k9d0s7aa"
                            ]
                          },
                          {
                            "type": "person",
                            "operator": "in",
                            "value": [
                              "p4hd8s0qk2l"
                            ]
                          }
                        ]
                      },
                      {
                        "type": "posture",
                        "field": "disk_encrypted",
                        "operator": "eq",
                        "value": true
                      }
                    ]
                  },
                  "enforced": true,
                  "enforcement_reason": null,
                  "enforcement_status": "active_at_edge",
                  "traffic_effect": "Allowed for the groups, people or devices it names — live at the edge now.",
                  "form_representable": true,
                  "form_view": {
                    "include": [
                      {
                        "type": "group",
                        "operator": "in",
                        "value": [
                          "g3k9d0s7aa"
                        ],
                        "resolved_groups": [
                          {
                            "id": "g3k9d0s7aa",
                            "display_name": "Finance",
                            "state": "active"
                          }
                        ]
                      },
                      {
                        "type": "person",
                        "operator": "in",
                        "value": [
                          "p4hd8s0qk2l"
                        ],
                        "resolved_people": [
                          {
                            "id": "p4hd8s0qk2l",
                            "display_name": "Omer Katz",
                            "email": "omer.katz@example.com",
                            "state": "active"
                          }
                        ]
                      }
                    ],
                    "require": [
                      {
                        "type": "posture",
                        "field": "disk_encrypted",
                        "operator": "eq",
                        "value": true
                      }
                    ],
                    "exclude": []
                  },
                  "version": 4,
                  "created_at": "2026-10-02T07:41:09.000Z",
                  "updated_at": "2026-10-13T09:24:11.000Z"
                }
              }
            }
          },
          "400": {
            "description": "`invalid-policy-rule`: The body fails validation; `detail` lists every problem as `path: message` (e.g. `match.children[1].value: posture disk_encrypted needs operator eq + boolean value`, `target: exactly one of service_id, service_role or private_network_id`, `target.service_id: unknown app`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-policy-rule": {
                    "summary": "The body fails validation; `detail` lists every problem as `path: message` (e.g. `match.children[1].value: posture disk_encrypted needs operator eq + boolean value`, `target: exactly one of service_id, service_role or private_network_id`, `target.service_id: unknown app`).",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-policy-rule",
                      "code": "invalid-policy-rule",
                      "title": "invalid policy rule",
                      "status": 400,
                      "detail": "The body fails validation; detail lists every problem as path: message (e.g. match.children[1].value: posture disk_encrypted needs operator eq + boolean value, target: exactly one of service_id, service_role or private_network_id, target.service_id: unknown app)."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`widening-console-only`: This change gives access: make it in the Cloudraw console.\n\n`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "widening-console-only": {
                    "summary": "This change gives access: make it in the Cloudraw console.",
                    "value": {
                      "type": "https://cloudraw.com/problems/widening-console-only",
                      "code": "widening-console-only",
                      "title": "widening console only",
                      "status": 403,
                      "detail": "This change gives access: make it in the Cloudraw console."
                    }
                  },
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`policy-rule-not-found`: No access rule with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "policy-rule-not-found": {
                    "summary": "No access rule with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/policy-rule-not-found",
                      "code": "policy-rule-not-found",
                      "title": "policy rule not found",
                      "status": 404,
                      "detail": "No access rule with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`version-conflict`: `If-Match` does not match the rule's current `version` (someone changed it meanwhile; re-read and retry).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "version-conflict": {
                    "summary": "`If-Match` does not match the rule's current `version` (someone changed it meanwhile; re-read and retry).",
                    "value": {
                      "type": "https://cloudraw.com/problems/version-conflict",
                      "code": "version-conflict",
                      "title": "version conflict",
                      "status": 409,
                      "detail": "If-Match does not match the rule's current version (someone changed it meanwhile; re-read and retry)."
                    }
                  }
                }
              }
            }
          },
          "428": {
            "description": "`if-match-required`: No `If-Match` header was sent.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "if-match-required": {
                    "summary": "No `If-Match` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/if-match-required",
                      "code": "if-match-required",
                      "title": "if match required",
                      "status": 428,
                      "detail": "No If-Match header was sent."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      },
      "delete": {
        "tags": [
          "Access rules"
        ],
        "operationId": "deletePolicyRule",
        "summary": "Delete an access rule",
        "description": "Deletes the rule and removes what it granted at the edge right away; devices that reached the app only through this rule lose access. Requires `If-Match`. Audited. A removal that gives access (a `deny`) is not done here: the answer is `409 use-the-remove-route` (see **Remove an access rule with a reason**).\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "rule_id",
            "in": "path",
            "required": true,
            "description": "Access rule id (from List access rules).",
            "schema": {
              "type": "string"
            },
            "example": "pr_7xk2m9c0d1"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "description": "The rule's current `version` (from a GET or the last write). Required: without it the call answers `428 if-match-required`; with a stale value `409 version-conflict`.",
            "schema": {
              "type": "string"
            },
            "example": "3"
          }
        ],
        "responses": {
          "202": {
            "description": "Deleted (`state: done`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                },
                "example": {
                  "id": "task_8k2x0m9s1d",
                  "tenant_id": "tq7x2m9k4ab",
                  "state": "done",
                  "result_uri": null,
                  "error": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`policy-rule-not-found`: No access rule with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "policy-rule-not-found": {
                    "summary": "No access rule with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/policy-rule-not-found",
                      "code": "policy-rule-not-found",
                      "title": "policy rule not found",
                      "status": 404,
                      "detail": "No access rule with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`version-conflict`: `If-Match` does not match the rule's current `version` (someone changed it meanwhile; re-read and retry).\n\n`use-the-remove-route`: Removing this rule gives access: use POST .../policy-rules/{rule_id}/remove with a reason.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "version-conflict": {
                    "summary": "`If-Match` does not match the rule's current `version` (someone changed it meanwhile; re-read and retry).",
                    "value": {
                      "type": "https://cloudraw.com/problems/version-conflict",
                      "code": "version-conflict",
                      "title": "version conflict",
                      "status": 409,
                      "detail": "If-Match does not match the rule's current version (someone changed it meanwhile; re-read and retry)."
                    }
                  },
                  "use-the-remove-route": {
                    "summary": "Removing this rule gives access: use POST .../policy-rules/{rule_id}/remove with a reason.",
                    "value": {
                      "type": "https://cloudraw.com/problems/use-the-remove-route",
                      "code": "use-the-remove-route",
                      "title": "use the remove route",
                      "status": 409,
                      "detail": "Removing this rule gives access: use POST .../policy-rules/{rule_id}/remove with a reason."
                    }
                  }
                }
              }
            }
          },
          "428": {
            "description": "`if-match-required`: No `If-Match` header was sent.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "if-match-required": {
                    "summary": "No `If-Match` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/if-match-required",
                      "code": "if-match-required",
                      "title": "if match required",
                      "status": 428,
                      "detail": "No If-Match header was sent."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/policy-rules/{rule_id}/remove": {
      "post": {
        "tags": [
          "Access rules"
        ],
        "operationId": "removePolicyRule",
        "summary": "Remove an access rule with a reason",
        "description": "Removes a rule whose removal gives access (a `deny`). The reason goes ONLY in the JSON body (`reason`, 10-300 characters counted after decoding; any language, one line; control characters and invalid UTF-8 are refused, bidi / format characters removed). Not in a header: `X-Cloudraw-Reason` together with a body reason is refused. API tokens cannot give access (`403 widening-console-only`): make the change in the Cloudraw console. Requires `If-Match`. Audited with the reason.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "rule_id",
            "in": "path",
            "required": true,
            "description": "Access rule id (from List access rules).",
            "schema": {
              "type": "string"
            },
            "example": "pr_7xk2m9c0d1"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "description": "The rule's current `version` (from a GET or the last write). Required: without it the call answers `428 if-match-required`; with a stale value `409 version-conflict`.",
            "schema": {
              "type": "string"
            },
            "example": "3"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string",
                    "description": "Why this removal gives access. 10-300 characters, one line."
                  }
                },
                "required": [
                  "reason"
                ]
              },
              "example": {
                "reason": "The contractor left; the block is no longer needed."
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Removed (`state: done`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                },
                "example": {
                  "id": "task_8k2x0m9s1d",
                  "tenant_id": "tq7x2m9k4ab",
                  "state": "done",
                  "result_uri": null,
                  "error": null
                }
              }
            }
          },
          "400": {
            "description": "`reason-required`: No reason, or not 10-300 characters.\n\n`reason-invalid`: The reason is not text, or has control characters or invalid UTF-8.\n\n`reason-header-and-body`: The reason was sent in a header and in the body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "reason-required": {
                    "summary": "No reason, or not 10-300 characters.",
                    "value": {
                      "type": "https://cloudraw.com/problems/reason-required",
                      "code": "reason-required",
                      "title": "reason required",
                      "status": 400,
                      "detail": "No reason, or not 10-300 characters."
                    }
                  },
                  "reason-invalid": {
                    "summary": "The reason is not text, or has control characters or invalid UTF-8.",
                    "value": {
                      "type": "https://cloudraw.com/problems/reason-invalid",
                      "code": "reason-invalid",
                      "title": "reason invalid",
                      "status": 400,
                      "detail": "The reason is not text, or has control characters or invalid UTF-8."
                    }
                  },
                  "reason-header-and-body": {
                    "summary": "The reason was sent in a header and in the body.",
                    "value": {
                      "type": "https://cloudraw.com/problems/reason-header-and-body",
                      "code": "reason-header-and-body",
                      "title": "reason header and body",
                      "status": 400,
                      "detail": "The reason was sent in a header and in the body."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`widening-console-only`: This removal gives access: make it in the Cloudraw console.\n\n`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "widening-console-only": {
                    "summary": "This removal gives access: make it in the Cloudraw console.",
                    "value": {
                      "type": "https://cloudraw.com/problems/widening-console-only",
                      "code": "widening-console-only",
                      "title": "widening console only",
                      "status": 403,
                      "detail": "This removal gives access: make it in the Cloudraw console."
                    }
                  },
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`policy-rule-not-found`: No access rule with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "policy-rule-not-found": {
                    "summary": "No access rule with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/policy-rule-not-found",
                      "code": "policy-rule-not-found",
                      "title": "policy rule not found",
                      "status": 404,
                      "detail": "No access rule with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`version-conflict`: `If-Match` does not match the rule's current `version` (someone changed it meanwhile; re-read and retry).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "version-conflict": {
                    "summary": "`If-Match` does not match the rule's current `version` (someone changed it meanwhile; re-read and retry).",
                    "value": {
                      "type": "https://cloudraw.com/problems/version-conflict",
                      "code": "version-conflict",
                      "title": "version conflict",
                      "status": 409,
                      "detail": "If-Match does not match the rule's current version (someone changed it meanwhile; re-read and retry)."
                    }
                  }
                }
              }
            }
          },
          "428": {
            "description": "`if-match-required`: No `If-Match` header was sent.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "if-match-required": {
                    "summary": "No `If-Match` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/if-match-required",
                      "code": "if-match-required",
                      "title": "if match required",
                      "status": 428,
                      "detail": "No If-Match header was sent."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/posture-profiles": {
      "get": {
        "tags": [
          "Device trust"
        ],
        "operationId": "listPostureProfiles",
        "summary": "List posture profiles",
        "description": "Returns your saved posture profiles (named sets of device-health checks) and the `catalog` of check names a profile may contain. Profiles are a saved list only: access and trust rules do not use them yet — put `posture` conditions in the rules themselves. Not paginated.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "responses": {
          "200": {
            "description": "Profiles and the check catalog.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PostureProfile"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Opaque cursor for the next page; null on the last page."
                    },
                    "catalog": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Check names a profile may contain."
                    }
                  },
                  "required": [
                    "items"
                  ]
                },
                "example": {
                  "items": [
                    {
                      "id": "pp_3k8x0s2m1d",
                      "name": "Finance laptops",
                      "conditions": [
                        "disk_encrypted",
                        "edr_present",
                        "firewall_on",
                        "os_up_to_date"
                      ],
                      "created_at": "2026-10-01T10:00:00.000Z",
                      "updated_at": null,
                      "version": 1
                    }
                  ],
                  "next_cursor": null,
                  "catalog": [
                    "disk_encrypted",
                    "antivirus_on",
                    "antivirus_present",
                    "edr_present",
                    "firewall_on",
                    "os_up_to_date",
                    "screen_lock",
                    "domain_or_entra_joined",
                    "managed_baseline",
                    "os_is_windows",
                    "os_is_macos"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      },
      "post": {
        "tags": [
          "Device trust"
        ],
        "operationId": "createPostureProfile",
        "summary": "Create a posture profile",
        "description": "Saves a named set of device-health checks. Duplicate check names are removed. Audited.\n\n**Token:** full access · **Created by:** owner\n\n**Idempotency:** send `Idempotency-Key` to retry safely — the same key and body within 24 h returns the first answer.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Up to 80 characters (longer names are cut)."
                  },
                  "conditions": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "At least one check name from the catalog."
                  }
                },
                "required": [
                  "name",
                  "conditions"
                ]
              },
              "example": {
                "name": "Finance laptops",
                "conditions": [
                  "disk_encrypted",
                  "edr_present",
                  "firewall_on",
                  "os_up_to_date"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The profile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PostureProfile"
                },
                "example": {
                  "id": "pp_3k8x0s2m1d",
                  "name": "Finance laptops",
                  "conditions": [
                    "disk_encrypted",
                    "edr_present",
                    "firewall_on",
                    "os_up_to_date"
                  ],
                  "created_at": "2026-10-01T10:00:00.000Z",
                  "updated_at": null,
                  "version": 1
                }
              }
            }
          },
          "400": {
            "description": "`name-required`: `name` is missing or blank.\n\n`conditions-required`: `conditions` is missing or empty.\n\n`conditions-must-be-strings`: `conditions` contains something other than strings.\n\n`unknown-condition`: A check name is not in the catalog; `detail` names it.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "name-required": {
                    "summary": "`name` is missing or blank.",
                    "value": {
                      "type": "https://cloudraw.com/problems/name-required",
                      "code": "name-required",
                      "title": "name required",
                      "status": 400,
                      "detail": "name is missing or blank."
                    }
                  },
                  "conditions-required": {
                    "summary": "`conditions` is missing or empty.",
                    "value": {
                      "type": "https://cloudraw.com/problems/conditions-required",
                      "code": "conditions-required",
                      "title": "conditions required",
                      "status": 400,
                      "detail": "conditions is missing or empty."
                    }
                  },
                  "conditions-must-be-strings": {
                    "summary": "`conditions` contains something other than strings.",
                    "value": {
                      "type": "https://cloudraw.com/problems/conditions-must-be-strings",
                      "code": "conditions-must-be-strings",
                      "title": "conditions must be strings",
                      "status": 400,
                      "detail": "conditions contains something other than strings."
                    }
                  },
                  "unknown-condition": {
                    "summary": "A check name is not in the catalog; `detail` names it.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unknown-condition",
                      "code": "unknown-condition",
                      "title": "unknown condition",
                      "status": 400,
                      "detail": "A check name is not in the catalog; detail names it."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`idempotency-key-reuse`: The same `Idempotency-Key` was used with a different body within 24 hours.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "idempotency-key-reuse": {
                    "summary": "The same `Idempotency-Key` was used with a different body within 24 hours.",
                    "value": {
                      "type": "https://cloudraw.com/problems/idempotency-key-reuse",
                      "code": "idempotency-key-reuse",
                      "title": "idempotency key reuse",
                      "status": 409,
                      "detail": "The same Idempotency-Key was used with a different body within 24 hours."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        },
        "x-cloudraw-idempotent": true
      }
    },
    "/v0/tenants/{tenant_id}/posture-profiles/{profile_id}": {
      "patch": {
        "tags": [
          "Device trust"
        ],
        "operationId": "updatePostureProfile",
        "summary": "Update a posture profile",
        "description": "Renames the profile and/or replaces its check list. A blank `name` is ignored. No `If-Match` is needed. Audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "profile_id",
            "in": "path",
            "required": true,
            "description": "Posture profile id.",
            "schema": {
              "type": "string"
            },
            "example": "pp_3k8x0s2m1d"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Up to 80 characters."
                  },
                  "conditions": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Replaces the list; at least one check name."
                  }
                }
              },
              "example": {
                "conditions": [
                  "disk_encrypted",
                  "edr_present",
                  "firewall_on",
                  "os_up_to_date",
                  "screen_lock"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated profile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PostureProfile"
                },
                "example": {
                  "id": "pp_3k8x0s2m1d",
                  "name": "Finance laptops",
                  "conditions": [
                    "disk_encrypted",
                    "edr_present",
                    "firewall_on",
                    "os_up_to_date",
                    "screen_lock"
                  ],
                  "created_at": "2026-10-01T10:00:00.000Z",
                  "updated_at": "2026-10-13T09:24:11.000Z",
                  "version": 2
                }
              }
            }
          },
          "400": {
            "description": "`conditions-required`: `conditions` is an empty list.\n\n`conditions-must-be-strings`: `conditions` contains something other than strings.\n\n`unknown-condition`: A check name is not in the catalog.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "conditions-required": {
                    "summary": "`conditions` is an empty list.",
                    "value": {
                      "type": "https://cloudraw.com/problems/conditions-required",
                      "code": "conditions-required",
                      "title": "conditions required",
                      "status": 400,
                      "detail": "conditions is an empty list."
                    }
                  },
                  "conditions-must-be-strings": {
                    "summary": "`conditions` contains something other than strings.",
                    "value": {
                      "type": "https://cloudraw.com/problems/conditions-must-be-strings",
                      "code": "conditions-must-be-strings",
                      "title": "conditions must be strings",
                      "status": 400,
                      "detail": "conditions contains something other than strings."
                    }
                  },
                  "unknown-condition": {
                    "summary": "A check name is not in the catalog.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unknown-condition",
                      "code": "unknown-condition",
                      "title": "unknown condition",
                      "status": 400,
                      "detail": "A check name is not in the catalog."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`profile-not-found`: No posture profile with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "profile-not-found": {
                    "summary": "No posture profile with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/profile-not-found",
                      "code": "profile-not-found",
                      "title": "profile not found",
                      "status": 404,
                      "detail": "No posture profile with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      },
      "delete": {
        "tags": [
          "Device trust"
        ],
        "operationId": "deletePostureProfile",
        "summary": "Delete a posture profile",
        "description": "Deletes the profile. Audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "profile_id",
            "in": "path",
            "required": true,
            "description": "Posture profile id.",
            "schema": {
              "type": "string"
            },
            "example": "pp_3k8x0s2m1d"
          }
        ],
        "responses": {
          "202": {
            "description": "Deleted (`state: done`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                },
                "example": {
                  "id": "task_8k2x0m9s1d",
                  "tenant_id": "tq7x2m9k4ab",
                  "state": "done",
                  "result_uri": null,
                  "error": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`profile-not-found`: No posture profile with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "profile-not-found": {
                    "summary": "No posture profile with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/profile-not-found",
                      "code": "profile-not-found",
                      "title": "profile not found",
                      "status": 404,
                      "detail": "No posture profile with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/private-networks": {
      "get": {
        "tags": [
          "Private networks"
        ],
        "operationId": "listPrivateNetworks",
        "summary": "List private networks",
        "description": "Returns every private network (IP ranges and DNS zones reached through a connector), oldest first, with how many access rules grant each one and any DNS findings. Not paginated (bounded by the plan's private-network limit).\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "responses": {
          "200": {
            "description": "All private networks.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrivateNetworkList"
                },
                "example": {
                  "items": [
                    {
                      "id": "pn_6b2x9q0wea",
                      "name": "HQ servers",
                      "connector_id": "cn0r4w8t2kq",
                      "connector_ids": [
                        "cn0r4w8t2kq"
                      ],
                      "cidrs": [
                        "10.20.0.0/16"
                      ],
                      "dns_zones": [
                        "corp.example.local"
                      ],
                      "dns_servers": [
                        "10.20.0.10"
                      ],
                      "dns_mode": "forward",
                      "translate": false,
                      "translated_cidr": null,
                      "guides": {
                        "network": {
                          "id": "network-private",
                          "section": null,
                          "title": "Private networks",
                          "url": "https://cdapi.cloudraw.com/guides/network-private",
                          "pdf_url": null
                        },
                        "cidr": {
                          "id": "network-private",
                          "section": null,
                          "title": "Private networks",
                          "url": "https://cdapi.cloudraw.com/guides/network-private",
                          "pdf_url": null
                        },
                        "translate": {
                          "id": "network-private",
                          "section": null,
                          "title": "Private networks",
                          "url": "https://cdapi.cloudraw.com/guides/network-private",
                          "pdf_url": null
                        }
                      },
                      "protocols": [
                        "tcp",
                        "udp"
                      ],
                      "port_ranges": [
                        {
                          "low": 1,
                          "high": 65535
                        }
                      ],
                      "require_trusted_device": true,
                      "access_rule_count": 0,
                      "notes": [
                        "Clients forward corp.example.local to 10.20.0.10 through the tunnel (client support: phase 2)."
                      ],
                      "dns_findings": [],
                      "status": {
                        "phase": "ready",
                        "observed_at": "2026-10-13T09:24:11.000Z",
                        "message": null
                      },
                      "version": 1,
                      "created_at": "2026-10-13T09:24:11.000Z",
                      "updated_at": "2026-10-13T09:24:11.000Z"
                    }
                  ],
                  "next_page": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      },
      "post": {
        "tags": [
          "Private networks"
        ],
        "operationId": "createPrivateNetwork",
        "summary": "Create a private network",
        "description": "Publishes whole IPv4 ranges (and optionally the DNS zones of that environment, such as an Active Directory domain) through a connector, for legacy access like RDP, SMB or LDAP to a subnet. Zero trust: it grants **no one** until an access rule targets it, and by default such rules also require a trusted device. With `dns_servers`, devices forward DNS for `dns_zones` to your own servers (full DNS, needed for a domain join); without, the connector resolves the names itself. Zones outside private space must be a domain this workspace verified by DNS TXT; such zones raise a security alert. Audited.\n\n**Token:** full access · **Created by:** owner\n\n**Idempotency:** send `Idempotency-Key` to retry safely — the same key and body within 24 h returns the first answer.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PrivateNetworkCreate"
              },
              "example": {
                "name": "HQ servers",
                "connector_id": "cn0r4w8t2kq",
                "cidrs": [
                  "10.20.0.0/16"
                ],
                "dns_zones": [
                  "corp.example.local"
                ],
                "dns_servers": [
                  "10.20.0.10"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new private network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrivateNetwork"
                },
                "example": {
                  "id": "pn_6b2x9q0wea",
                  "name": "HQ servers",
                  "connector_id": "cn0r4w8t2kq",
                  "connector_ids": [
                    "cn0r4w8t2kq"
                  ],
                  "cidrs": [
                    "10.20.0.0/16"
                  ],
                  "dns_zones": [
                    "corp.example.local"
                  ],
                  "dns_servers": [
                    "10.20.0.10"
                  ],
                  "dns_mode": "forward",
                  "translate": false,
                  "translated_cidr": null,
                  "guides": {
                    "network": {
                      "id": "network-private",
                      "section": null,
                      "title": "Private networks",
                      "url": "https://cdapi.cloudraw.com/guides/network-private",
                      "pdf_url": null
                    },
                    "cidr": {
                      "id": "network-private",
                      "section": null,
                      "title": "Private networks",
                      "url": "https://cdapi.cloudraw.com/guides/network-private",
                      "pdf_url": null
                    },
                    "translate": {
                      "id": "network-private",
                      "section": null,
                      "title": "Private networks",
                      "url": "https://cdapi.cloudraw.com/guides/network-private",
                      "pdf_url": null
                    }
                  },
                  "protocols": [
                    "tcp",
                    "udp"
                  ],
                  "port_ranges": [
                    {
                      "low": 1,
                      "high": 65535
                    }
                  ],
                  "require_trusted_device": true,
                  "access_rule_count": 0,
                  "notes": [
                    "Clients forward corp.example.local to 10.20.0.10 through the tunnel (client support: phase 2)."
                  ],
                  "dns_findings": [],
                  "status": {
                    "phase": "ready",
                    "observed_at": "2026-10-13T09:24:11.000Z",
                    "message": null
                  },
                  "version": 1,
                  "created_at": "2026-10-13T09:24:11.000Z",
                  "updated_at": "2026-10-13T09:24:11.000Z"
                }
              }
            }
          },
          "400": {
            "description": "`invalid-private-network`: A field is invalid. `errors[]` lists each `{path, message}`; a CIDR with host bits set also carries `suggestions` (e.g. `10.20.5.0/24`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-private-network": {
                    "summary": "A field is invalid. `errors[]` lists each `{path, message}`; a CIDR with host bits set also carries `suggestions` (e.g. `10.20.5.0/24`).",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-private-network",
                      "code": "invalid-private-network",
                      "title": "invalid private network",
                      "status": 400,
                      "detail": "A field is invalid. errors[] lists each {path, message}; a CIDR with host bits set also carries suggestions (e.g. 10.20.5.0/24)."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`private-network-quota-reached`: The workspace has reached its plan's private-network limit (default 5).\n\n`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "private-network-quota-reached": {
                    "summary": "The workspace has reached its plan's private-network limit (default 5).",
                    "value": {
                      "type": "https://cloudraw.com/problems/private-network-quota-reached",
                      "code": "private-network-quota-reached",
                      "title": "private network quota reached",
                      "status": 403,
                      "detail": "The workspace has reached its plan's private-network limit (default 5)."
                    }
                  },
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`private-network-name-taken`: Another private network already uses this name.\n\n`name-conflicts-with-a-connection`: The name collides with an application's internal name; choose another name.\n\n`cidr-overlaps-another-private-network`: A range overlaps a range of another private network; `conflict` names it.\n\n`no-translated-range-left`: Translation is on and the workspace has used all translated address ranges.\n\n`idempotency-key-reuse`: The same `Idempotency-Key` was used with a different body within 24 hours.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "private-network-name-taken": {
                    "summary": "Another private network already uses this name.",
                    "value": {
                      "type": "https://cloudraw.com/problems/private-network-name-taken",
                      "code": "private-network-name-taken",
                      "title": "private network name taken",
                      "status": 409,
                      "detail": "Another private network already uses this name."
                    }
                  },
                  "name-conflicts-with-a-connection": {
                    "summary": "The name collides with an application's internal name; choose another name.",
                    "value": {
                      "type": "https://cloudraw.com/problems/name-conflicts-with-a-connection",
                      "code": "name-conflicts-with-a-connection",
                      "title": "name conflicts with a connection",
                      "status": 409,
                      "detail": "The name collides with an application's internal name; choose another name."
                    }
                  },
                  "cidr-overlaps-another-private-network": {
                    "summary": "A range overlaps a range of another private network; `conflict` names it.",
                    "value": {
                      "type": "https://cloudraw.com/problems/cidr-overlaps-another-private-network",
                      "code": "cidr-overlaps-another-private-network",
                      "title": "cidr overlaps another private network",
                      "status": 409,
                      "detail": "A range overlaps a range of another private network; conflict names it."
                    }
                  },
                  "no-translated-range-left": {
                    "summary": "Translation is on and the workspace has used all translated address ranges.",
                    "value": {
                      "type": "https://cloudraw.com/problems/no-translated-range-left",
                      "code": "no-translated-range-left",
                      "title": "no translated range left",
                      "status": 409,
                      "detail": "Translation is on and the workspace has used all translated address ranges."
                    }
                  },
                  "idempotency-key-reuse": {
                    "summary": "The same `Idempotency-Key` was used with a different body within 24 hours.",
                    "value": {
                      "type": "https://cloudraw.com/problems/idempotency-key-reuse",
                      "code": "idempotency-key-reuse",
                      "title": "idempotency key reuse",
                      "status": 409,
                      "detail": "The same Idempotency-Key was used with a different body within 24 hours."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`provisioning-failed`: The network could not be set up right now; nothing was created. Retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "provisioning-failed": {
                    "summary": "The network could not be set up right now; nothing was created. Retry.",
                    "value": {
                      "type": "https://cloudraw.com/problems/provisioning-failed",
                      "code": "provisioning-failed",
                      "title": "provisioning failed",
                      "status": 502,
                      "detail": "The network could not be set up right now; nothing was created. Retry."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        },
        "x-cloudraw-idempotent": true
      }
    },
    "/v0/tenants/{tenant_id}/private-networks/{network_id}": {
      "get": {
        "tags": [
          "Private networks"
        ],
        "operationId": "getPrivateNetwork",
        "summary": "Get a private network",
        "description": "Returns one private network (same shape as in the list).\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "network_id",
            "in": "path",
            "required": true,
            "description": "Private network id.",
            "schema": {
              "type": "string"
            },
            "example": "pn_6b2x9q0wea"
          }
        ],
        "responses": {
          "200": {
            "description": "The private network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrivateNetwork"
                },
                "example": {
                  "id": "pn_6b2x9q0wea",
                  "name": "HQ servers",
                  "connector_id": "cn0r4w8t2kq",
                  "connector_ids": [
                    "cn0r4w8t2kq"
                  ],
                  "cidrs": [
                    "10.20.0.0/16"
                  ],
                  "dns_zones": [
                    "corp.example.local"
                  ],
                  "dns_servers": [
                    "10.20.0.10"
                  ],
                  "dns_mode": "forward",
                  "translate": false,
                  "translated_cidr": null,
                  "guides": {
                    "network": {
                      "id": "network-private",
                      "section": null,
                      "title": "Private networks",
                      "url": "https://cdapi.cloudraw.com/guides/network-private",
                      "pdf_url": null
                    },
                    "cidr": {
                      "id": "network-private",
                      "section": null,
                      "title": "Private networks",
                      "url": "https://cdapi.cloudraw.com/guides/network-private",
                      "pdf_url": null
                    },
                    "translate": {
                      "id": "network-private",
                      "section": null,
                      "title": "Private networks",
                      "url": "https://cdapi.cloudraw.com/guides/network-private",
                      "pdf_url": null
                    }
                  },
                  "protocols": [
                    "tcp",
                    "udp"
                  ],
                  "port_ranges": [
                    {
                      "low": 1,
                      "high": 65535
                    }
                  ],
                  "require_trusted_device": true,
                  "access_rule_count": 0,
                  "notes": [
                    "Clients forward corp.example.local to 10.20.0.10 through the tunnel (client support: phase 2)."
                  ],
                  "dns_findings": [],
                  "status": {
                    "phase": "ready",
                    "observed_at": "2026-10-13T09:24:11.000Z",
                    "message": null
                  },
                  "version": 1,
                  "created_at": "2026-10-13T09:24:11.000Z",
                  "updated_at": "2026-10-13T09:24:11.000Z"
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`private-network-not-found`: No private network with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "private-network-not-found": {
                    "summary": "No private network with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/private-network-not-found",
                      "code": "private-network-not-found",
                      "title": "private network not found",
                      "status": 404,
                      "detail": "No private network with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      },
      "patch": {
        "tags": [
          "Private networks"
        ],
        "operationId": "updatePrivateNetwork",
        "summary": "Update a private network",
        "description": "Changes the name, ranges, DNS zones / servers, protocols, ports, hosting connectors, translation or the trusted-device requirement. Changes apply live and existing access rules keep pointing at the network; changing `require_trusted_device` re-applies every rule that grants it. The primary `connector_id` cannot be changed (create a new network instead). A DNS change is audited and, outside private space, raises a security alert. If an update fails half-way, the previous settings are kept. Send `If-Match: <version>` to fail with `409 version-conflict` instead of overwriting a change made in the meantime.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "network_id",
            "in": "path",
            "required": true,
            "description": "Private network id.",
            "schema": {
              "type": "string"
            },
            "example": "pn_6b2x9q0wea"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PrivateNetworkUpdate"
              },
              "example": {
                "cidrs": [
                  "10.20.0.0/16",
                  "10.30.0.0/24"
                ],
                "require_trusted_device": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated private network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrivateNetwork"
                },
                "example": {
                  "id": "pn_6b2x9q0wea",
                  "name": "HQ servers",
                  "connector_id": "cn0r4w8t2kq",
                  "connector_ids": [
                    "cn0r4w8t2kq"
                  ],
                  "cidrs": [
                    "10.20.0.0/16",
                    "10.30.0.0/24"
                  ],
                  "dns_zones": [
                    "corp.example.local"
                  ],
                  "dns_servers": [
                    "10.20.0.10"
                  ],
                  "dns_mode": "forward",
                  "translate": false,
                  "translated_cidr": null,
                  "guides": {
                    "network": {
                      "id": "network-private",
                      "section": null,
                      "title": "Private networks",
                      "url": "https://cdapi.cloudraw.com/guides/network-private",
                      "pdf_url": null
                    },
                    "cidr": {
                      "id": "network-private",
                      "section": null,
                      "title": "Private networks",
                      "url": "https://cdapi.cloudraw.com/guides/network-private",
                      "pdf_url": null
                    },
                    "translate": {
                      "id": "network-private",
                      "section": null,
                      "title": "Private networks",
                      "url": "https://cdapi.cloudraw.com/guides/network-private",
                      "pdf_url": null
                    }
                  },
                  "protocols": [
                    "tcp",
                    "udp"
                  ],
                  "port_ranges": [
                    {
                      "low": 1,
                      "high": 65535
                    }
                  ],
                  "require_trusted_device": true,
                  "access_rule_count": 0,
                  "notes": [
                    "Clients forward corp.example.local to 10.20.0.10 through the tunnel (client support: phase 2)."
                  ],
                  "dns_findings": [],
                  "status": {
                    "phase": "ready",
                    "observed_at": "2026-10-13T09:24:11.000Z",
                    "message": null
                  },
                  "version": 2,
                  "created_at": "2026-10-13T09:24:11.000Z",
                  "updated_at": "2026-10-13T09:24:11.000Z"
                }
              }
            }
          },
          "400": {
            "description": "`invalid-private-network`: A field is invalid, unknown, `connector_id` was sent, or the body changes nothing. `errors[]` lists each `{path, message}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-private-network": {
                    "summary": "A field is invalid, unknown, `connector_id` was sent, or the body changes nothing. `errors[]` lists each `{path, message}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-private-network",
                      "code": "invalid-private-network",
                      "title": "invalid private network",
                      "status": 400,
                      "detail": "A field is invalid, unknown, connector_id was sent, or the body changes nothing. errors[] lists each {path, message}."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`private-network-not-found`: No private network with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "private-network-not-found": {
                    "summary": "No private network with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/private-network-not-found",
                      "code": "private-network-not-found",
                      "title": "private network not found",
                      "status": 404,
                      "detail": "No private network with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`version-conflict`: `If-Match` does not match the current `version`.\n\n`cidr-overlaps-another-private-network`: A new range overlaps a range of another private network.\n\n`no-translated-range-left`: Translation is on and the workspace has used all translated address ranges.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "version-conflict": {
                    "summary": "`If-Match` does not match the current `version`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/version-conflict",
                      "code": "version-conflict",
                      "title": "version conflict",
                      "status": 409,
                      "detail": "If-Match does not match the current version."
                    }
                  },
                  "cidr-overlaps-another-private-network": {
                    "summary": "A new range overlaps a range of another private network.",
                    "value": {
                      "type": "https://cloudraw.com/problems/cidr-overlaps-another-private-network",
                      "code": "cidr-overlaps-another-private-network",
                      "title": "cidr overlaps another private network",
                      "status": 409,
                      "detail": "A new range overlaps a range of another private network."
                    }
                  },
                  "no-translated-range-left": {
                    "summary": "Translation is on and the workspace has used all translated address ranges.",
                    "value": {
                      "type": "https://cloudraw.com/problems/no-translated-range-left",
                      "code": "no-translated-range-left",
                      "title": "no translated range left",
                      "status": 409,
                      "detail": "Translation is on and the workspace has used all translated address ranges."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`provisioning-failed`: The change could not be applied right now; the previous settings were kept. Retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "provisioning-failed": {
                    "summary": "The change could not be applied right now; the previous settings were kept. Retry.",
                    "value": {
                      "type": "https://cloudraw.com/problems/provisioning-failed",
                      "code": "provisioning-failed",
                      "title": "provisioning failed",
                      "status": 502,
                      "detail": "The change could not be applied right now; the previous settings were kept. Retry."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      },
      "delete": {
        "tags": [
          "Private networks"
        ],
        "operationId": "deletePrivateNetwork",
        "summary": "Delete a private network",
        "description": "Removes the private network. Every access rule that targets it is revoked and deleted first, so no grant is left behind. Cannot be undone. Audited. The answer is a finished task.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "network_id",
            "in": "path",
            "required": true,
            "description": "Private network id.",
            "schema": {
              "type": "string"
            },
            "example": "pn_6b2x9q0wea"
          }
        ],
        "responses": {
          "202": {
            "description": "Deleted (the task is already `done`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                },
                "example": {
                  "id": "task_8k2m0x9s1d",
                  "tenant_id": "tq7x2m9k4ab",
                  "state": "done",
                  "result_uri": null,
                  "error": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`private-network-not-found`: No private network with this id in the workspace.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "private-network-not-found": {
                    "summary": "No private network with this id in the workspace.",
                    "value": {
                      "type": "https://cloudraw.com/problems/private-network-not-found",
                      "code": "private-network-not-found",
                      "title": "private network not found",
                      "status": 404,
                      "detail": "No private network with this id in the workspace."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`delete-failed`: The network could not be removed right now (if the message says so, its access rules were already revoked). Retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "delete-failed": {
                    "summary": "The network could not be removed right now (if the message says so, its access rules were already revoked). Retry.",
                    "value": {
                      "type": "https://cloudraw.com/problems/delete-failed",
                      "code": "delete-failed",
                      "title": "delete failed",
                      "status": 502,
                      "detail": "The network could not be removed right now (if the message says so, its access rules were already revoked). Retry."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/protection-status": {
      "get": {
        "tags": [
          "Reports"
        ],
        "operationId": "getProtectionStatus",
        "summary": "Get protection status",
        "description": "One line per protection (second step at sign-in, device trust, access rules, allowed apps, recording, browser controls, file protection, web filtering, remembered Windows sign-in): whether it is configured, and whether Cloudraw really applies it everywhere it is configured. `partial` comes with a `scope` naming where it is applied, and `coverage` counts how many of the configured items are covered. Read-only: nothing is created or saved. If the sign-in service cannot be reached, the `second_step` item is left out of the answer rather than guessed.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "responses": {
          "200": {
            "description": "Protection status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtectionStatus"
                },
                "example": {
                  "checked_at": "2026-10-13T09:24:11.000Z",
                  "items": [
                    {
                      "key": "second_step",
                      "configured": true,
                      "enforcement": "partial",
                      "scope": "workspace_sign_in_only",
                      "coverage": {
                        "enforced": 21,
                        "total": 23
                      }
                    },
                    {
                      "key": "device_trust",
                      "configured": true,
                      "enforcement": "enforced",
                      "scope": null,
                      "coverage": null
                    },
                    {
                      "key": "access_rules",
                      "configured": true,
                      "enforcement": "enforced",
                      "scope": null,
                      "coverage": {
                        "enforced": 12,
                        "total": 12
                      }
                    },
                    {
                      "key": "app_firewall",
                      "configured": true,
                      "enforcement": "partial",
                      "scope": "client_min_version",
                      "coverage": {
                        "enforced": 14,
                        "total": 17
                      }
                    },
                    {
                      "key": "recording",
                      "configured": true,
                      "enforcement": "partial",
                      "scope": "browser_sessions_only",
                      "coverage": {
                        "enforced": 1,
                        "total": 3
                      }
                    },
                    {
                      "key": "browser_controls",
                      "configured": true,
                      "enforcement": "partial",
                      "scope": "browser_sessions_only",
                      "coverage": {
                        "enforced": 1,
                        "total": 4
                      }
                    },
                    {
                      "key": "file_protection",
                      "configured": false,
                      "enforcement": "not_enforced",
                      "scope": null,
                      "coverage": null
                    },
                    {
                      "key": "web_filtering",
                      "configured": false,
                      "enforcement": "not_available",
                      "scope": null,
                      "coverage": null
                    },
                    {
                      "key": "remembered_sign_in",
                      "configured": false,
                      "enforcement": "not_enforced",
                      "scope": null,
                      "coverage": null
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/provisioning-tokens": {
      "get": {
        "tags": [
          "Connectors"
        ],
        "operationId": "listProvisioningTokens",
        "summary": "List provisioning tokens",
        "description": "Lists the provisioning tokens used to deploy Cloudraw Connect silently to many machines (GPO, Intune, SCCM). Only a prefix of each token is shown; revoked tokens stay in the list with `revoked: true`.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "responses": {
          "200": {
            "description": "All provisioning tokens (not paginated).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProvisioningTokenList"
                },
                "example": {
                  "items": [
                    {
                      "id": "prov_k2x9m0s8",
                      "name": "Intune rollout",
                      "prefix": "crwp_Q7xk2…",
                      "created_by": "dana.levi@example.com",
                      "created_at": "2026-10-13T09:24:11.000Z",
                      "expires_at": "2026-11-12T09:24:11.000Z",
                      "revoked": false,
                      "uses": 37,
                      "max_uses": 250
                    }
                  ],
                  "next_page": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      },
      "post": {
        "tags": [
          "Connectors"
        ],
        "operationId": "createProvisioningToken",
        "summary": "Create a provisioning token",
        "description": "Creates a reusable token for unattended Cloudraw Connect installs, and returns the preset file and silent install command to push to your machines. Each machine enrolls itself on first launch with its own one-time code. Mass-enrolled devices start untrusted (no access) until your trust rules pass. The token is shown only in this answer; treat the preset file as a secret. Audited.\n\n**Token:** full access · **Created by:** owner\n\n**Idempotency:** send `Idempotency-Key`. The answer carries a secret shown once: a retry with the same key answers `409 already-issued` instead of the secret.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Label, up to 80 characters. Default `Fleet deploy`."
                  },
                  "ttl_days": {
                    "type": "integer",
                    "description": "Lifetime in days, 1-365. Default 30.",
                    "minimum": 1,
                    "maximum": 365
                  },
                  "max_uses": {
                    "type": [
                      "integer",
                      "null"
                    ],
                    "minimum": 1,
                    "maximum": 100000,
                    "description": "How many devices may enroll with it; null (default) = unlimited."
                  }
                }
              },
              "example": {
                "name": "Intune rollout",
                "ttl_days": 30,
                "max_uses": 250
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created. `token` is shown once.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProvisioningTokenCreated"
                },
                "example": {
                  "id": "prov_k2x9m0s8",
                  "name": "Intune rollout",
                  "prefix": "crwp_Q7xk2…",
                  "created_by": "dana.levi@example.com",
                  "created_at": "2026-10-13T09:24:11.000Z",
                  "expires_at": "2026-11-12T09:24:11.000Z",
                  "revoked": false,
                  "uses": 0,
                  "max_uses": 250,
                  "token": "crwp_xxxxxxxxxxxxxxxxxxxxxxxxxx",
                  "install": {
                    "client_version": "0.4.9",
                    "download_url": "https://downloads.cloudraw.com/download/cloudraw-connect-setup-0.4.9.exe",
                    "preset": {
                      "schema": 1,
                      "workspace": "northwind",
                      "signin": "code",
                      "enrollment_url": "https://cdapi.cloudraw.com/pub/provision?token=crwp_Q7xk2m9d0s8a1w4e6r2t5y8u3i",
                      "managed_by": "Northwind Logistics"
                    },
                    "preset_path": "C:\\Windows\\Temp\\cloudraw-preset.json",
                    "installed_preset_path": "C:\\ProgramData\\Cloudraw Connect\\preset.json",
                    "windows": "cloudraw-connect-setup-0.4.9.exe /S /PRESET=\"C:\\Windows\\Temp\\cloudraw-preset.json\"",
                    "msi": null,
                    "note": "Push the preset file to the machine, then run the installer silently (GPO / Intune / SCCM / startup script). Each machine enrolls itself on first launch with its own one-time code. Mass-enrolled devices are untrusted (dark) until your trust rules pass. Treat the preset file as a secret: it carries the provisioning token.",
                    "provision_endpoint": "https://cdapi.cloudraw.com/pub/provision"
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid-ttl-days`: `ttl_days` is not an integer 1-365.\n\n`invalid-max-uses`: `max_uses` is not null or an integer 1-100000.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-ttl-days": {
                    "summary": "`ttl_days` is not an integer 1-365.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-ttl-days",
                      "code": "invalid-ttl-days",
                      "title": "invalid ttl days",
                      "status": 400,
                      "detail": "ttl_days is not an integer 1-365."
                    }
                  },
                  "invalid-max-uses": {
                    "summary": "`max_uses` is not null or an integer 1-100000.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-max-uses",
                      "code": "invalid-max-uses",
                      "title": "invalid max uses",
                      "status": 400,
                      "detail": "max_uses is not null or an integer 1-100000."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`idempotency-key-reuse`: The same `Idempotency-Key` was used with a different body within 24 hours.\n\n`already-issued`: This `Idempotency-Key` already created a secret; it is shown only once. Retry with a new key.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "idempotency-key-reuse": {
                    "summary": "The same `Idempotency-Key` was used with a different body within 24 hours.",
                    "value": {
                      "type": "https://cloudraw.com/problems/idempotency-key-reuse",
                      "code": "idempotency-key-reuse",
                      "title": "idempotency key reuse",
                      "status": 409,
                      "detail": "The same Idempotency-Key was used with a different body within 24 hours."
                    }
                  },
                  "already-issued": {
                    "summary": "This `Idempotency-Key` already created a secret; it is shown only once. Retry with a new key.",
                    "value": {
                      "type": "https://cloudraw.com/problems/already-issued",
                      "code": "already-issued",
                      "title": "already issued",
                      "status": 409,
                      "detail": "This Idempotency-Key already created a secret; it is shown only once. Retry with a new key."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        },
        "x-cloudraw-idempotent": "secret"
      }
    },
    "/v0/tenants/{tenant_id}/provisioning-tokens/{token_id}": {
      "delete": {
        "tags": [
          "Connectors"
        ],
        "operationId": "revokeProvisioningToken",
        "summary": "Revoke a provisioning token",
        "description": "Revokes the token at once: machines that have not enrolled yet can no longer enroll with it. Devices already enrolled are not affected. The token stays in the list as revoked. Audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "token_id",
            "in": "path",
            "required": true,
            "description": "Provisioning token id (from `GET …/provisioning-tokens`).",
            "schema": {
              "type": "string"
            },
            "example": "prov_k2x9m0s8"
          }
        ],
        "responses": {
          "202": {
            "description": "Revoked (the task is already done).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                },
                "example": {
                  "id": "task_8k2x0m9s",
                  "tenant_id": "tq7x2m9k4ab",
                  "state": "done",
                  "result_uri": null,
                  "error": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`provisioning-token-not-found`: No provisioning token with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "provisioning-token-not-found": {
                    "summary": "No provisioning token with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/provisioning-token-not-found",
                      "code": "provisioning-token-not-found",
                      "title": "provisioning token not found",
                      "status": 404,
                      "detail": "No provisioning token with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/security-events": {
      "get": {
        "tags": [
          "Alerts"
        ],
        "operationId": "listSecurityEvents",
        "summary": "List security events",
        "description": "Returns the Security Center feed: denied access attempts, blocked or quarantined file transfers and other enforcement events, newest first, with their triage state and workspace-wide counters. Not paginated: use `limit` (at most 500) and the filters. The workspace keeps its newest 2000 events.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "description": "Only this category (for example `blocked`, `files`).",
            "schema": {
              "type": "string"
            },
            "example": "blocked"
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "Only events at or after this time (ISO 8601, UTC, as returned in `at`).",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-10-13T00:00:00.000Z"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Triage filter: `open` (= `new` + `acknowledged`, the work queue), `all` (default), or a comma-separated list of statuses (`new,acknowledged,resolved,dismissed`).",
            "schema": {
              "type": "string"
            },
            "example": "open"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum items, newest first. Default 100, at most 500.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            },
            "example": 100
          }
        ],
        "responses": {
          "200": {
            "description": "The events.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SecurityEventList"
                },
                "example": {
                  "items": [
                    {
                      "id": "sev_9x2k0m8s1d",
                      "at": "2026-10-13T09:24:11.000Z",
                      "category": "blocked",
                      "severity": "warn",
                      "actor": "dana.levi@example.com",
                      "device": "LAPTOP-7Q2M",
                      "target_app": "finance-erp",
                      "reason": "Device posture: disk encryption off",
                      "triage": {
                        "status": "new",
                        "assignee": null,
                        "acknowledged_by": null,
                        "acknowledged_at": null,
                        "resolution": null,
                        "suppressed_by": null,
                        "history": []
                      }
                    }
                  ],
                  "counts": {
                    "today": 14,
                    "today_blocked": 11,
                    "open": 6,
                    "new": 4
                  },
                  "next_page": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/security-events/{event_id}/acknowledge": {
      "post": {
        "tags": [
          "Alerts"
        ],
        "operationId": "acknowledgeSecurityEvent",
        "summary": "Acknowledge a security event",
        "description": "Takes ownership of a `new` alert: status becomes `acknowledged` and `assignee` is set (the caller unless you name someone). The step is added to the security event's triage history, written to the audit log and streamed to your SIEM destinations. Triage never deletes an event (the workspace keeps its newest 2000 security events).\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "event_id",
            "in": "path",
            "required": true,
            "description": "Security event id.",
            "schema": {
              "type": "string"
            },
            "example": "sev_9x2k0m8s1d"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "assignee": {
                    "type": "string",
                    "description": "Who owns it (up to 160 characters). Default: the caller."
                  },
                  "note": {
                    "type": "string",
                    "description": "Up to 1000 characters."
                  }
                }
              },
              "example": {
                "assignee": "omer.katz@example.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The alert with its new triage state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertTriageResult"
                },
                "example": {
                  "id": "sev_9x2k0m8s1d",
                  "kind": "security_event",
                  "severity": "warn",
                  "triage": {
                    "status": "acknowledged",
                    "assignee": "dana.levi@example.com",
                    "acknowledged_by": "dana.levi@example.com",
                    "acknowledged_at": "2026-10-13T09:24:11.000Z",
                    "resolution": null,
                    "suppressed_by": null,
                    "history": [
                      {
                        "at": "2026-10-13T09:24:11.000Z",
                        "by": "dana.levi@example.com",
                        "action": "acknowledge",
                        "from": "new",
                        "to": "acknowledged",
                        "reason": null,
                        "note": null
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`security-event-not-found`: No security event with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "security-event-not-found": {
                    "summary": "No security event with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/security-event-not-found",
                      "code": "security-event-not-found",
                      "title": "security event not found",
                      "status": 404,
                      "detail": "No security event with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`invalid-transition`: The alert is not `new`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-transition": {
                    "summary": "The alert is not `new`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-transition",
                      "code": "invalid-transition",
                      "title": "invalid transition",
                      "status": 409,
                      "detail": "The alert is not new."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/security-events/{event_id}/dismiss": {
      "post": {
        "tags": [
          "Alerts"
        ],
        "operationId": "dismissSecurityEvent",
        "summary": "Dismiss a security event",
        "description": "Closes a `new` or `acknowledged` alert as not needing action (status `dismissed`). A `reason` is required, and a `note` too when the alert severity is `bad`. The step is added to the security event's triage history, written to the audit log and streamed to your SIEM destinations. Triage never deletes an event (the workspace keeps its newest 2000 security events).\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "event_id",
            "in": "path",
            "required": true,
            "description": "Security event id.",
            "schema": {
              "type": "string"
            },
            "example": "sev_9x2k0m8s1d"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string",
                    "enum": [
                      "false_positive",
                      "expected_activity",
                      "benign",
                      "duplicate",
                      "accepted_risk"
                    ]
                  },
                  "note": {
                    "type": "string",
                    "description": "Why (up to 1000 characters). Required when the alert severity is `bad`."
                  }
                },
                "required": [
                  "reason"
                ]
              },
              "example": {
                "reason": "expected_activity",
                "note": "Quarterly penetration test by our vendor."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The alert with its new triage state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertTriageResult"
                },
                "example": {
                  "id": "sev_9x2k0m8s1d",
                  "kind": "security_event",
                  "severity": "warn",
                  "triage": {
                    "status": "dismissed",
                    "assignee": null,
                    "acknowledged_by": null,
                    "acknowledged_at": null,
                    "resolution": {
                      "kind": "dismissed",
                      "reason": "expected_activity",
                      "note": "Quarterly penetration test by our vendor.",
                      "by": "dana.levi@example.com",
                      "at": "2026-10-13T09:24:11.000Z"
                    },
                    "suppressed_by": null,
                    "history": [
                      {
                        "at": "2026-10-13T09:24:11.000Z",
                        "by": "dana.levi@example.com",
                        "action": "dismiss",
                        "from": "new",
                        "to": "dismissed",
                        "reason": "expected_activity",
                        "note": null
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "`reason-required`: `reason` is missing or not one of the allowed values.\n\n`note-required`: The alert severity is `bad` and no `note` was given.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "reason-required": {
                    "summary": "`reason` is missing or not one of the allowed values.",
                    "value": {
                      "type": "https://cloudraw.com/problems/reason-required",
                      "code": "reason-required",
                      "title": "reason required",
                      "status": 400,
                      "detail": "reason is missing or not one of the allowed values."
                    }
                  },
                  "note-required": {
                    "summary": "The alert severity is `bad` and no `note` was given.",
                    "value": {
                      "type": "https://cloudraw.com/problems/note-required",
                      "code": "note-required",
                      "title": "note required",
                      "status": 400,
                      "detail": "The alert severity is bad and no note was given."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`security-event-not-found`: No security event with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "security-event-not-found": {
                    "summary": "No security event with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/security-event-not-found",
                      "code": "security-event-not-found",
                      "title": "security event not found",
                      "status": 404,
                      "detail": "No security event with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`invalid-transition`: The alert is already resolved or dismissed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-transition": {
                    "summary": "The alert is already resolved or dismissed.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-transition",
                      "code": "invalid-transition",
                      "title": "invalid transition",
                      "status": 409,
                      "detail": "The alert is already resolved or dismissed."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/security-events/{event_id}/reopen": {
      "post": {
        "tags": [
          "Alerts"
        ],
        "operationId": "reopenSecurityEvent",
        "summary": "Reopen a security event",
        "description": "Puts a `resolved` or `dismissed` alert back to `new` and clears its resolution. The step is added to the security event's triage history, written to the audit log and streamed to your SIEM destinations. Triage never deletes an event (the workspace keeps its newest 2000 security events).\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "event_id",
            "in": "path",
            "required": true,
            "description": "Security event id.",
            "schema": {
              "type": "string"
            },
            "example": "sev_9x2k0m8s1d"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "note": {
                    "type": "string",
                    "description": "Up to 1000 characters."
                  }
                }
              },
              "example": {
                "note": "Recurred after the fix."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The alert with its new triage state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertTriageResult"
                },
                "example": {
                  "id": "sev_9x2k0m8s1d",
                  "kind": "security_event",
                  "severity": "warn",
                  "triage": {
                    "status": "new",
                    "assignee": null,
                    "acknowledged_by": null,
                    "acknowledged_at": null,
                    "resolution": null,
                    "suppressed_by": null,
                    "history": [
                      {
                        "at": "2026-10-13T09:24:11.000Z",
                        "by": "dana.levi@example.com",
                        "action": "reopen",
                        "from": "resolved",
                        "to": "new",
                        "reason": null,
                        "note": "Recurred after the fix."
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`security-event-not-found`: No security event with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "security-event-not-found": {
                    "summary": "No security event with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/security-event-not-found",
                      "code": "security-event-not-found",
                      "title": "security event not found",
                      "status": 404,
                      "detail": "No security event with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`invalid-transition`: The alert is not resolved or dismissed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-transition": {
                    "summary": "The alert is not resolved or dismissed.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-transition",
                      "code": "invalid-transition",
                      "title": "invalid transition",
                      "status": 409,
                      "detail": "The alert is not resolved or dismissed."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/security-events/{event_id}/resolve": {
      "post": {
        "tags": [
          "Alerts"
        ],
        "operationId": "resolveSecurityEvent",
        "summary": "Resolve a security event",
        "description": "Closes a `new` or `acknowledged` alert as handled (status `resolved`). The step is added to the security event's triage history, written to the audit log and streamed to your SIEM destinations. Triage never deletes an event (the workspace keeps its newest 2000 security events).\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "event_id",
            "in": "path",
            "required": true,
            "description": "Security event id.",
            "schema": {
              "type": "string"
            },
            "example": "sev_9x2k0m8s1d"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "note": {
                    "type": "string",
                    "description": "Up to 1000 characters."
                  }
                }
              },
              "example": {
                "note": "Device re-encrypted; access works again."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The alert with its new triage state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertTriageResult"
                },
                "example": {
                  "id": "sev_9x2k0m8s1d",
                  "kind": "security_event",
                  "severity": "warn",
                  "triage": {
                    "status": "resolved",
                    "assignee": null,
                    "acknowledged_by": null,
                    "acknowledged_at": null,
                    "resolution": {
                      "kind": "resolved",
                      "reason": null,
                      "note": "Device re-encrypted; access works again.",
                      "by": "dana.levi@example.com",
                      "at": "2026-10-13T09:24:11.000Z"
                    },
                    "suppressed_by": null,
                    "history": [
                      {
                        "at": "2026-10-13T09:24:11.000Z",
                        "by": "dana.levi@example.com",
                        "action": "resolve",
                        "from": "new",
                        "to": "resolved",
                        "reason": null,
                        "note": null
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`security-event-not-found`: No security event with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "security-event-not-found": {
                    "summary": "No security event with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/security-event-not-found",
                      "code": "security-event-not-found",
                      "title": "security event not found",
                      "status": 404,
                      "detail": "No security event with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`invalid-transition`: The alert is already resolved or dismissed.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-transition": {
                    "summary": "The alert is already resolved or dismissed.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-transition",
                      "code": "invalid-transition",
                      "title": "invalid transition",
                      "status": 409,
                      "detail": "The alert is already resolved or dismissed."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/sessions": {
      "get": {
        "tags": [
          "Sessions"
        ],
        "operationId": "listSessions",
        "summary": "List live sessions",
        "description": "Returns every session open right now in your workspace: who is connected, from which device, to which app or private network, and through which Cloudraw edge. Cloudraw Connect's automatic reachability checks are left out. If live sessions cannot be read at the moment, `overlay` is `unavailable` and the list holds only portal-reported sessions — check that field before concluding nobody is connected.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "connection_id",
            "in": "query",
            "required": false,
            "description": "Only sessions to this app (connection). An unknown id returns an empty list.",
            "schema": {
              "type": "string"
            },
            "example": "cx9m2v7d1pa"
          },
          {
            "name": "app",
            "in": "query",
            "required": false,
            "description": "Only sessions to the app or private network with this exact name. Ignored when `connection_id` is sent.",
            "schema": {
              "type": "string"
            },
            "example": "Finance RDP"
          }
        ],
        "responses": {
          "200": {
            "description": "The live sessions (not paginated).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LiveSessionList"
                },
                "example": {
                  "items": [
                    {
                      "id": "ovl_7f3k9x2m0qd8s1a",
                      "source": "overlay",
                      "state": "active",
                      "user": "Dana Levi",
                      "device": "DANA-LAPTOP",
                      "app": "Finance RDP",
                      "recording": true,
                      "path": "edge-1 → edge-3",
                      "edge": "edge-1",
                      "lat_ms": null,
                      "started_at": "2026-10-13T08:51:40.000Z",
                      "connection_id": "cx9m2v7d1pa",
                      "private_network_id": null,
                      "device_id": "dvc_5mxq2b7r8k",
                      "person_id": "pz81kd03mna",
                      "jit_grant_id": null,
                      "routers": [
                        "edge-1",
                        "edge-3"
                      ],
                      "kind": "device"
                    }
                  ],
                  "counts_by_app": {
                    "Finance RDP": 1
                  },
                  "overlay": "ok",
                  "next_page": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/sessions/{session_id}": {
      "delete": {
        "tags": [
          "Sessions"
        ],
        "operationId": "endSession",
        "summary": "End a session",
        "description": "Cuts a live session immediately on the Cloudraw network. The device can reconnect at once if its access still allows it — to keep it out, also remove its access, quarantine the device or suspend the person. The action is written to the audit log (`session.kill`) with the reason and note you send. The body is optional; without it the reason is `ADMIN_TERMINATED`.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "description": "Session id from `GET …/sessions` (`ovl_…` or `ses_…`).",
            "schema": {
              "type": "string"
            },
            "example": "ovl_7f3k9x2m0qd8s1a"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string",
                    "enum": [
                      "ADMIN_TERMINATED",
                      "SECURITY_INCIDENT",
                      "POLICY_REVOKED",
                      "REAUTH_REQUIRED",
                      "POSTURE_FAILED"
                    ],
                    "description": "Why the session is ended. Default `ADMIN_TERMINATED`."
                  },
                  "note": {
                    "type": "string",
                    "description": "Free text for the audit log; longer text is cut at 300 characters.",
                    "maxLength": 300
                  }
                }
              },
              "example": {
                "reason": "SECURITY_INCIDENT",
                "note": "Laptop reported stolen"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The session was ended (the task is already `done`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                },
                "example": {
                  "id": "task_4k9x2m0s8d1q",
                  "tenant_id": "tq7x2m9k4ab",
                  "state": "done",
                  "result_uri": null,
                  "error": null
                }
              }
            }
          },
          "400": {
            "description": "`invalid-reason`: `reason` is not one of the listed codes.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-reason": {
                    "summary": "`reason` is not one of the listed codes.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-reason",
                      "code": "invalid-reason",
                      "title": "invalid reason",
                      "status": 400,
                      "detail": "reason is not one of the listed codes."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`session-not-found`: No active session with this id (it may have ended already).\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "session-not-found": {
                    "summary": "No active session with this id (it may have ended already).",
                    "value": {
                      "type": "https://cloudraw.com/problems/session-not-found",
                      "code": "session-not-found",
                      "title": "session not found",
                      "status": 404,
                      "detail": "No active session with this id (it may have ended already)."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`end-session-failed`: The session could not be ended right now. Retry.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "end-session-failed": {
                    "summary": "The session could not be ended right now. Retry.",
                    "value": {
                      "type": "https://cloudraw.com/problems/end-session-failed",
                      "code": "end-session-failed",
                      "title": "end session failed",
                      "status": 502,
                      "detail": "The session could not be ended right now. Retry."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/siem": {
      "get": {
        "tags": [
          "Log streaming"
        ],
        "operationId": "listLogDestinations",
        "summary": "List log streaming destinations",
        "description": "Returns your SIEM / log destinations with their delivery status, plus the supported types, streams and setup guides. Secret settings are always masked.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "responses": {
          "200": {
            "description": "The destinations.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiemDestinationList"
                },
                "example": {
                  "items": [
                    {
                      "id": "siem_2k9x0d8s1m",
                      "type": "splunk",
                      "config": {
                        "url": "https://splunk.example.com:8088/services/collector/event",
                        "hec_token": "••••••••",
                        "index": "cloudraw",
                        "sourcetype": null
                      },
                      "streams": [
                        "audit",
                        "alerts"
                      ],
                      "status": "configured",
                      "created_at": "2026-10-13T09:24:11.000Z",
                      "last_event": null,
                      "guide": {
                        "id": "siem-splunk",
                        "section": null,
                        "title": "Stream logs to Splunk",
                        "url": "https://docs.example.com/guides/siem-splunk",
                        "pdf_url": null
                      },
                      "delivery": null,
                      "audit_shipping": {
                        "cursor": null
                      }
                    }
                  ],
                  "types": [
                    "splunk",
                    "sentinel",
                    "datadog",
                    "s3",
                    "syslog",
                    "http"
                  ],
                  "type_guides": {
                    "splunk": {
                      "id": "siem-splunk",
                      "section": null,
                      "title": "Stream logs to Splunk",
                      "url": "https://docs.example.com/guides/siem-splunk",
                      "pdf_url": null
                    }
                  },
                  "guide": null,
                  "streams": [
                    "audit",
                    "alerts"
                  ],
                  "next_page": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      },
      "post": {
        "tags": [
          "Log streaming"
        ],
        "operationId": "createLogDestination",
        "summary": "Add a log streaming destination",
        "description": "Starts streaming your audit log and/or alerts to a SIEM or log store. The audit stream starts from now (no history is back-filled), is delivered at least once in batches of up to 100, and survives outages: a failing destination is retried with backoff and you get an alert after 15 minutes of failures. At most 10 destinations. Secrets are encrypted at rest and never returned. Audited (without the secrets).\n\n`config` by `type` (unknown keys are dropped):\n- `splunk`: `url` (HEC endpoint, https), `hec_token`; optional `index`, `sourcetype`.\n- `datadog`: `key` (API key); optional `site` (`datadoghq.com` default, `us3.datadoghq.com`, `us5.datadoghq.com`, `datadoghq.eu`, `ap1.datadoghq.com`, `ap2.datadoghq.com`, `ddog-gov.com`), `service`.\n- `sentinel` (Microsoft Sentinel / Azure Monitor Logs ingestion): `tenant_id` and `client_id` (GUIDs), `client_secret`, `endpoint` (`https://….ingest.monitor.azure.com`), `dcr_immutable_id` (`dcr-<32 hex>`), `stream_name` (`Custom-<Table>`).\n- `s3`: `bucket` (lowercase, no dots), `region` (like `eu-central-1`), `access_key`, `secret_key`; optional `prefix`.\n- `syslog` (RFC 5425 over TLS): `host` (public DNS name or IPv4), `port` (default 6514); optional `ca_pem` (a CA certificate for a private CA).\n- `http`: `url` (https); optional `token` (sent as a bearer token).\n\nURLs must be public https endpoints on an allowed port (443, 8088, 8443).\n\n**Token:** full access · **Created by:** owner\n\n**Idempotency:** send `Idempotency-Key` to retry safely — the same key and body within 24 h returns the first answer.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "splunk",
                      "sentinel",
                      "datadog",
                      "s3",
                      "syslog",
                      "http"
                    ]
                  },
                  "config": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Settings for the type (see above)."
                  },
                  "streams": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "audit",
                        "alerts"
                      ]
                    },
                    "description": "Non-empty. Default: both."
                  }
                },
                "required": [
                  "type",
                  "config"
                ]
              },
              "example": {
                "type": "splunk",
                "config": {
                  "url": "https://splunk.example.com:8088/services/collector/event",
                  "hec_token": "0f6c2b9e-4d1a-4c7e-9b8a-2e5d7f1c3a90",
                  "index": "cloudraw"
                },
                "streams": [
                  "audit",
                  "alerts"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The destination (secrets masked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiemDestination"
                },
                "example": {
                  "id": "siem_2k9x0d8s1m",
                  "type": "splunk",
                  "config": {
                    "url": "https://splunk.example.com:8088/services/collector/event",
                    "hec_token": "••••••••",
                    "index": "cloudraw",
                    "sourcetype": null
                  },
                  "streams": [
                    "audit",
                    "alerts"
                  ],
                  "status": "configured",
                  "created_at": "2026-10-13T09:24:11.000Z",
                  "last_event": null,
                  "guide": {
                    "id": "siem-splunk",
                    "section": null,
                    "title": "Stream logs to Splunk",
                    "url": "https://docs.example.com/guides/siem-splunk",
                    "pdf_url": null
                  },
                  "delivery": null,
                  "audit_shipping": {
                    "cursor": null
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid-type`: `type` is not a supported destination type.\n\n`config-object-required`: `config` is not an object.\n\n`invalid-streams`: `streams` is empty or contains something other than `audit` / `alerts`.\n\n`invalid-siem-config`: A required setting is missing or invalid (URL not allowed, bad GUID, bucket name …); `detail` says which.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-type": {
                    "summary": "`type` is not a supported destination type.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-type",
                      "code": "invalid-type",
                      "title": "invalid type",
                      "status": 400,
                      "detail": "type is not a supported destination type."
                    }
                  },
                  "config-object-required": {
                    "summary": "`config` is not an object.",
                    "value": {
                      "type": "https://cloudraw.com/problems/config-object-required",
                      "code": "config-object-required",
                      "title": "config object required",
                      "status": 400,
                      "detail": "config is not an object."
                    }
                  },
                  "invalid-streams": {
                    "summary": "`streams` is empty or contains something other than `audit` / `alerts`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-streams",
                      "code": "invalid-streams",
                      "title": "invalid streams",
                      "status": 400,
                      "detail": "streams is empty or contains something other than audit / alerts."
                    }
                  },
                  "invalid-siem-config": {
                    "summary": "A required setting is missing or invalid (URL not allowed, bad GUID, bucket name …); `detail` says which.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-siem-config",
                      "code": "invalid-siem-config",
                      "title": "invalid siem config",
                      "status": 400,
                      "detail": "A required setting is missing or invalid (URL not allowed, bad GUID, bucket name …); detail says which."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`siem-destination-limit`: The workspace already has 10 destinations.\n\n`idempotency-key-reuse`: The same `Idempotency-Key` was used with a different body within 24 hours.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "siem-destination-limit": {
                    "summary": "The workspace already has 10 destinations.",
                    "value": {
                      "type": "https://cloudraw.com/problems/siem-destination-limit",
                      "code": "siem-destination-limit",
                      "title": "siem destination limit",
                      "status": 409,
                      "detail": "The workspace already has 10 destinations."
                    }
                  },
                  "idempotency-key-reuse": {
                    "summary": "The same `Idempotency-Key` was used with a different body within 24 hours.",
                    "value": {
                      "type": "https://cloudraw.com/problems/idempotency-key-reuse",
                      "code": "idempotency-key-reuse",
                      "title": "idempotency key reuse",
                      "status": 409,
                      "detail": "The same Idempotency-Key was used with a different body within 24 hours."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`secret-storage-unavailable`: Secrets cannot be stored safely right now. Retry later.\n\n`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "secret-storage-unavailable": {
                    "summary": "Secrets cannot be stored safely right now. Retry later.",
                    "value": {
                      "type": "https://cloudraw.com/problems/secret-storage-unavailable",
                      "code": "secret-storage-unavailable",
                      "title": "secret storage unavailable",
                      "status": 503,
                      "detail": "Secrets cannot be stored safely right now. Retry later."
                    }
                  },
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        },
        "x-cloudraw-idempotent": true
      }
    },
    "/v0/tenants/{tenant_id}/siem/{destination_id}": {
      "delete": {
        "tags": [
          "Log streaming"
        ],
        "operationId": "deleteLogDestination",
        "summary": "Remove a log streaming destination",
        "description": "Stops streaming to the destination at once (queued events for it are dropped) and deletes its stored credentials. Audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "destination_id",
            "in": "path",
            "required": true,
            "description": "Log streaming destination id.",
            "schema": {
              "type": "string"
            },
            "example": "siem_2k9x0d8s1m"
          }
        ],
        "responses": {
          "202": {
            "description": "Done (the task is already complete).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                },
                "example": {
                  "id": "task_8s2k0x9m1d",
                  "tenant_id": "tq7x2m9k4ab",
                  "state": "done",
                  "result_uri": null,
                  "error": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`destination-not-found`: No destination with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "destination-not-found": {
                    "summary": "No destination with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/destination-not-found",
                      "code": "destination-not-found",
                      "title": "destination not found",
                      "status": 404,
                      "detail": "No destination with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/siem/{destination_id}/test": {
      "post": {
        "tags": [
          "Log streaming"
        ],
        "operationId": "testLogDestination",
        "summary": "Send a test event",
        "description": "Sends one test event (action `siem.test`) to the destination now and reports the answer — no retries. Sets the destination `status` to `streaming` or `error`. Audited.\n\n**Token:** full access · **Created by:** owner\n\n**Rate limit:** 10 test events per hour per destination.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "destination_id",
            "in": "path",
            "required": true,
            "description": "Log streaming destination id.",
            "schema": {
              "type": "string"
            },
            "example": "siem_2k9x0d8s1m"
          }
        ],
        "responses": {
          "200": {
            "description": "The result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "configured",
                        "streaming",
                        "error"
                      ]
                    },
                    "error": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "What the destination answered on failure."
                    }
                  },
                  "required": [
                    "ok",
                    "status"
                  ]
                },
                "example": {
                  "ok": true,
                  "status": "streaming",
                  "error": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`destination-not-found`: No destination with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "destination-not-found": {
                    "summary": "No destination with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/destination-not-found",
                      "code": "destination-not-found",
                      "title": "destination not found",
                      "status": 404,
                      "detail": "No destination with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`test-rate-limited`: More than 10 test events for this destination this hour.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "test-rate-limited": {
                    "summary": "More than 10 test events for this destination this hour.",
                    "value": {
                      "type": "https://cloudraw.com/problems/test-rate-limited",
                      "code": "test-rate-limited",
                      "title": "test rate limited",
                      "status": 429,
                      "detail": "More than 10 test events for this destination this hour."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`test-failed`: The test could not be sent; `detail` says why.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "test-failed": {
                    "summary": "The test could not be sent; `detail` says why.",
                    "value": {
                      "type": "https://cloudraw.com/problems/test-failed",
                      "code": "test-failed",
                      "title": "test failed",
                      "status": 500,
                      "detail": "The test could not be sent; detail says why."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        },
        "x-cloudraw-rate-limit": "10 test events per hour per destination."
      }
    },
    "/v0/tenants/{tenant_id}/support-cases": {
      "get": {
        "tags": [
          "Support"
        ],
        "operationId": "listSupportCases",
        "summary": "List support cases",
        "description": "Lists your workspace's support cases: diagnostics that Cloudraw Connect or a connector sent, with their status and the conversation with Cloudraw support. Only summaries are returned, never the raw logs.\n\nTwo modes. **Display** (default): newest activity first, at most `limit` cases (default and maximum 500), `next_cursor` is always null and `has_more` says whether cases were cut off. **Polling** (send `cursor`, `updated_since` or `order=updated`): cases in ascending `updated_at` order, `limit` per page (maximum 500); keep calling with `next_cursor` until `has_more` is false. Polling never skips a case, so use it to mirror cases into another system. When the last page is empty, `next_cursor` stays the cursor you sent, so you can store it and poll again later.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only cases in this status.",
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "in_progress",
                "waiting_customer",
                "waiting_cloudraw",
                "resolved",
                "closed"
              ]
            },
            "example": "waiting_customer"
          },
          {
            "name": "updated_since",
            "in": "query",
            "required": false,
            "description": "Only cases updated strictly after this time (ISO 8601). Starts polling mode.",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-10-01T00:00:00Z"
          },
          {
            "name": "order",
            "in": "query",
            "required": false,
            "description": "`updated` switches to polling mode (ascending by last update).",
            "schema": {
              "type": "string",
              "enum": [
                "updated"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size, 1-500 (default 500).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500
            },
            "example": 100
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Polling mode: pass back `next_cursor` from the previous page, unchanged.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Cases.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SupportCaseList"
                },
                "example": {
                  "items": [
                    {
                      "case_id": "SC-4K7M2Q",
                      "code": "7KQ2M9X4D8R1T",
                      "product": "connect",
                      "client_version": "0.4.8",
                      "os": "Windows 11 23H2",
                      "diagnosis": {
                        "code": "tunnel.dns.unreachable",
                        "cause": "The internal DNS server 10.20.0.10 did not answer."
                      },
                      "status": "waiting_customer",
                      "status_label": "Waiting for you",
                      "attribution": "cert",
                      "attached_via": null,
                      "device": {
                        "id": "dvc_5mxq2b7r8k",
                        "name": "LT-DANA-02",
                        "kind": "device"
                      },
                      "counters": {
                        "reports": 2
                      },
                      "reports": [
                        {
                          "code": "7KQ2M9X4D8R1T",
                          "received_at": "2026-10-12T07:41:02.000Z",
                          "client_version": "0.4.8"
                        },
                        {
                          "code": "M3D8K1Q7X2R9V",
                          "received_at": "2026-10-13T08:02:44.000Z",
                          "client_version": "0.4.8"
                        }
                      ],
                      "created_at": "2026-10-12T07:41:02.000Z",
                      "last_seen": "2026-10-13T08:02:44.000Z",
                      "updated_at": "2026-10-13T09:24:11.000Z",
                      "status_changed_at": "2026-10-13T09:24:11.000Z",
                      "staff_access": [
                        {
                          "at": "2026-10-12T09:15:00.000Z",
                          "reason": "Checking the DNS errors in the log",
                          "text": "Cloudraw staff opened the full log of case SC-4K7M2Q on 2026-10-12"
                        }
                      ],
                      "messages": [
                        {
                          "id": "m_2k9x0d8s",
                          "at": "2026-10-13T09:24:11.000Z",
                          "by": "support",
                          "author": "Cloudraw support",
                          "kind": "reply",
                          "text": "Is 10.20.0.10 reachable from the connector host? Please check and reply here."
                        }
                      ],
                      "known_issue": null,
                      "can_reply": true,
                      "response_time": {
                        "text": "We reply within 1 business day."
                      }
                    }
                  ],
                  "has_more": false,
                  "next_cursor": "WyIyMDI2LTEwLTEzVDA5OjI0OjExLjAwMFoiLCJTQy00SzdNMlEiXQ",
                  "total": 1,
                  "generated_at": "2026-10-13T09:24:11.000Z",
                  "response_time": {
                    "text": "We reply within 1 business day."
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid-cursor`: `cursor` is not a `next_cursor` value returned by this endpoint.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-cursor": {
                    "summary": "`cursor` is not a `next_cursor` value returned by this endpoint.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-cursor",
                      "code": "invalid-cursor",
                      "title": "invalid cursor",
                      "status": 400,
                      "detail": "cursor is not a next_cursor value returned by this endpoint."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/support-cases/{case_id}": {
      "get": {
        "tags": [
          "Support"
        ],
        "operationId": "getSupportCase",
        "summary": "Get a support case",
        "description": "Returns one support case: summary, status, report list, staff log access and the conversation with Cloudraw support. The raw diagnostics log is never returned. Replying to a case is done in the Cloudraw console.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "case_id",
            "in": "path",
            "required": true,
            "description": "Case number (`SC-…`).",
            "schema": {
              "type": "string"
            },
            "example": "SC-4K7M2Q"
          }
        ],
        "responses": {
          "200": {
            "description": "The case.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SupportCase"
                },
                "example": {
                  "case_id": "SC-4K7M2Q",
                  "code": "7KQ2M9X4D8R1T",
                  "product": "connect",
                  "client_version": "0.4.8",
                  "os": "Windows 11 23H2",
                  "diagnosis": {
                    "code": "tunnel.dns.unreachable",
                    "cause": "The internal DNS server 10.20.0.10 did not answer."
                  },
                  "status": "waiting_customer",
                  "status_label": "Waiting for you",
                  "attribution": "cert",
                  "attached_via": null,
                  "device": {
                    "id": "dvc_5mxq2b7r8k",
                    "name": "LT-DANA-02",
                    "kind": "device"
                  },
                  "counters": {
                    "reports": 2
                  },
                  "reports": [
                    {
                      "code": "7KQ2M9X4D8R1T",
                      "received_at": "2026-10-12T07:41:02.000Z",
                      "client_version": "0.4.8"
                    },
                    {
                      "code": "M3D8K1Q7X2R9V",
                      "received_at": "2026-10-13T08:02:44.000Z",
                      "client_version": "0.4.8"
                    }
                  ],
                  "created_at": "2026-10-12T07:41:02.000Z",
                  "last_seen": "2026-10-13T08:02:44.000Z",
                  "updated_at": "2026-10-13T09:24:11.000Z",
                  "status_changed_at": "2026-10-13T09:24:11.000Z",
                  "staff_access": [
                    {
                      "at": "2026-10-12T09:15:00.000Z",
                      "reason": "Checking the DNS errors in the log",
                      "text": "Cloudraw staff opened the full log of case SC-4K7M2Q on 2026-10-12"
                    }
                  ],
                  "messages": [
                    {
                      "id": "m_2k9x0d8s",
                      "at": "2026-10-13T09:24:11.000Z",
                      "by": "support",
                      "author": "Cloudraw support",
                      "kind": "reply",
                      "text": "Is 10.20.0.10 reachable from the connector host? Please check and reply here."
                    }
                  ],
                  "known_issue": null,
                  "can_reply": true,
                  "response_time": {
                    "text": "We reply within 1 business day."
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`case-not-found`: No case with this number in your workspace (it may have been deleted on request).\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "case-not-found": {
                    "summary": "No case with this number in your workspace (it may have been deleted on request).",
                    "value": {
                      "type": "https://cloudraw.com/problems/case-not-found",
                      "code": "case-not-found",
                      "title": "case not found",
                      "status": 404,
                      "detail": "No case with this number in your workspace (it may have been deleted on request)."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/trust-rules": {
      "get": {
        "tags": [
          "Device trust"
        ],
        "operationId": "listTrustRules",
        "summary": "List trust rules",
        "description": "Returns every trust rule, oldest first. A device is **trusted** when it matches at least one enabled trust rule (or an admin marked it trusted). With no trust rules at all, devices are not trusted but are not blocked either. Pages like **List access rules**: pass `limit`, then `cursor` = the previous `next_cursor`; without `limit` every rule comes back.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size, 1-200 (above 200 = 200). Leave it out to get every rule in one answer.",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 50
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "The `next_cursor` of the previous page, unchanged.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Trust rules (one page when `limit` is set).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TrustRule"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Opaque cursor for the next page; null on the last page."
                    }
                  },
                  "required": [
                    "items"
                  ]
                },
                "example": {
                  "items": [
                    {
                      "id": "tr_4m8s2k0x9q",
                      "name": "Company laptops",
                      "match": {
                        "op": "and",
                        "children": [
                          {
                            "type": "posture",
                            "field": "computer_type",
                            "operator": "in",
                            "value": [
                              "domain"
                            ]
                          },
                          {
                            "type": "posture",
                            "field": "disk_encrypted",
                            "operator": "eq",
                            "value": true
                          },
                          {
                            "type": "posture",
                            "field": "edr_present",
                            "operator": "eq",
                            "value": true
                          }
                        ]
                      },
                      "enabled": true,
                      "form_representable": true,
                      "form_view": {
                        "include": [],
                        "require": [
                          {
                            "type": "posture",
                            "field": "computer_type",
                            "operator": "in",
                            "value": [
                              "domain"
                            ]
                          },
                          {
                            "type": "posture",
                            "field": "disk_encrypted",
                            "operator": "eq",
                            "value": true
                          },
                          {
                            "type": "posture",
                            "field": "edr_present",
                            "operator": "eq",
                            "value": true
                          }
                        ],
                        "exclude": []
                      },
                      "version": 2,
                      "created_at": "2026-09-20T09:00:00.000Z",
                      "updated_at": "2026-10-13T09:24:11.000Z"
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "description": "`invalid-limit`: `limit` is not a whole number of at least 1.\n\n`invalid-cursor`: `cursor` is not a `next_cursor` from this list.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-limit": {
                    "summary": "`limit` is not a whole number of at least 1.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-limit",
                      "code": "invalid-limit",
                      "title": "invalid limit",
                      "status": 400,
                      "detail": "limit is not a whole number of at least 1."
                    }
                  },
                  "invalid-cursor": {
                    "summary": "`cursor` is not a `next_cursor` from this list.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-cursor",
                      "code": "invalid-cursor",
                      "title": "invalid cursor",
                      "status": 400,
                      "detail": "cursor is not a next_cursor from this list."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      },
      "post": {
        "tags": [
          "Device trust"
        ],
        "operationId": "createTrustRule",
        "summary": "Create a trust rule",
        "description": "Creates a trust rule and re-evaluates every device right away. Devices that become trusted or untrusted get their access updated immediately and raise an alert. Use **Test a draft trust rule** first to see who would gain or lose trust. Audited.\n\n**Token:** full access · **Created by:** owner\n\n**Idempotency:** send `Idempotency-Key` to retry safely — the same key and body within 24 h returns the first answer.\n\nConditions use the same tree as access rules (see **Create an access rule**). In trust rules `group not_in`, `os_in` and `network` leaves are evaluated too; `time`, `mfa`, `app` and `attribute` leaves are never met yet.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "1-128 characters."
                  },
                  "match": {
                    "$ref": "#/components/schemas/ConditionNode"
                  },
                  "enabled": {
                    "type": "boolean",
                    "description": "Default true."
                  }
                },
                "required": [
                  "name",
                  "match"
                ]
              },
              "example": {
                "name": "Company laptops",
                "match": {
                  "op": "and",
                  "children": [
                    {
                      "type": "posture",
                      "field": "computer_type",
                      "operator": "in",
                      "value": [
                        "domain"
                      ]
                    },
                    {
                      "type": "posture",
                      "field": "disk_encrypted",
                      "operator": "eq",
                      "value": true
                    },
                    {
                      "type": "posture",
                      "field": "edr_present",
                      "operator": "eq",
                      "value": true
                    }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The rule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrustRule"
                },
                "example": {
                  "id": "tr_4m8s2k0x9q",
                  "name": "Company laptops",
                  "match": {
                    "op": "and",
                    "children": [
                      {
                        "type": "posture",
                        "field": "computer_type",
                        "operator": "in",
                        "value": [
                          "domain"
                        ]
                      },
                      {
                        "type": "posture",
                        "field": "disk_encrypted",
                        "operator": "eq",
                        "value": true
                      },
                      {
                        "type": "posture",
                        "field": "edr_present",
                        "operator": "eq",
                        "value": true
                      }
                    ]
                  },
                  "enabled": true,
                  "form_representable": true,
                  "form_view": {
                    "include": [],
                    "require": [
                      {
                        "type": "posture",
                        "field": "computer_type",
                        "operator": "in",
                        "value": [
                          "domain"
                        ]
                      },
                      {
                        "type": "posture",
                        "field": "disk_encrypted",
                        "operator": "eq",
                        "value": true
                      },
                      {
                        "type": "posture",
                        "field": "edr_present",
                        "operator": "eq",
                        "value": true
                      }
                    ],
                    "exclude": []
                  },
                  "version": 1,
                  "created_at": "2026-09-20T09:00:00.000Z",
                  "updated_at": "2026-09-20T09:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "`invalid-trust-rule`: The body fails validation; `detail` lists every problem as `path: message`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-trust-rule": {
                    "summary": "The body fails validation; `detail` lists every problem as `path: message`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-trust-rule",
                      "code": "invalid-trust-rule",
                      "title": "invalid trust rule",
                      "status": 400,
                      "detail": "The body fails validation; detail lists every problem as path: message."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`idempotency-key-reuse`: The same `Idempotency-Key` was used with a different body within 24 hours.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "idempotency-key-reuse": {
                    "summary": "The same `Idempotency-Key` was used with a different body within 24 hours.",
                    "value": {
                      "type": "https://cloudraw.com/problems/idempotency-key-reuse",
                      "code": "idempotency-key-reuse",
                      "title": "idempotency key reuse",
                      "status": 409,
                      "detail": "The same Idempotency-Key was used with a different body within 24 hours."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        },
        "x-cloudraw-idempotent": true
      }
    },
    "/v0/tenants/{tenant_id}/trust-rules:evaluate": {
      "post": {
        "tags": [
          "Device trust"
        ],
        "operationId": "evaluateTrustRule",
        "summary": "Test a draft trust rule",
        "description": "Validates a draft trust rule without saving it and shows which devices it matches now, and who would gain or lose trust compared with today (other enabled rules still count; devices an admin marked manually or quarantined are left out). When editing a rule, pass its id as `replaces` so its current version is not counted.\n\n**Token:** read-only or full access · **Created by:** owner or security admin\n\nValidation problems come back as `compiles: false` with `errors` (status 200).",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "match": {
                    "$ref": "#/components/schemas/ConditionNode"
                  },
                  "replaces": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Id of the trust rule this draft would replace."
                  }
                },
                "required": [
                  "match"
                ]
              },
              "example": {
                "match": {
                  "op": "and",
                  "children": [
                    {
                      "type": "posture",
                      "field": "computer_type",
                      "operator": "in",
                      "value": [
                        "domain"
                      ]
                    },
                    {
                      "type": "posture",
                      "field": "disk_encrypted",
                      "operator": "eq",
                      "value": true
                    },
                    {
                      "type": "posture",
                      "field": "edr_present",
                      "operator": "eq",
                      "value": true
                    }
                  ]
                },
                "replaces": "tr_4m8s2k0x9q"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The dry-run result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrustRuleEvaluation"
                },
                "example": {
                  "compiles": true,
                  "errors": [],
                  "form_representable": true,
                  "form_view": {
                    "include": [],
                    "require": [
                      {
                        "type": "posture",
                        "field": "computer_type",
                        "operator": "in",
                        "value": [
                          "domain"
                        ]
                      },
                      {
                        "type": "posture",
                        "field": "disk_encrypted",
                        "operator": "eq",
                        "value": true
                      },
                      {
                        "type": "posture",
                        "field": "edr_present",
                        "operator": "eq",
                        "value": true
                      }
                    ],
                    "exclude": []
                  },
                  "match_count": 12,
                  "sample_matches": [
                    {
                      "device_id": "dvc_5mxq2b7r8k",
                      "device_name": "FIN-LT-014",
                      "person": "Dana Levi",
                      "os": "Windows 11 Pro 24H2",
                      "trust_now": "trusted",
                      "trust_source": "rule",
                      "reason": "matched trust rule \"Company laptops\""
                    }
                  ],
                  "would_gain": [],
                  "would_lose": [
                    {
                      "device_id": "dvc_8k0s2m9x4q",
                      "device_name": "HR-LT-003",
                      "person": "Omer Katz",
                      "os": "Windows 11 Pro",
                      "trust_now": "trusted",
                      "trust_source": "rule",
                      "reason": "matched trust rule \"Company laptops\""
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/trust-rules/{rule_id}": {
      "patch": {
        "tags": [
          "Device trust"
        ],
        "operationId": "updateTrustRule",
        "summary": "Update a trust rule",
        "description": "Changes `name`, `match` and/or `enabled` (a non-boolean `enabled` is ignored). Every device is re-evaluated right away. Requires `If-Match`. Audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "rule_id",
            "in": "path",
            "required": true,
            "description": "Trust rule id (from List trust rules).",
            "schema": {
              "type": "string"
            },
            "example": "tr_4m8s2k0x9q"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "description": "The rule's current `version` (from a GET or the last write). Required: without it the call answers `428 if-match-required`; with a stale value `409 version-conflict`.",
            "schema": {
              "type": "string"
            },
            "example": "3"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "1-128 characters."
                  },
                  "match": {
                    "$ref": "#/components/schemas/ConditionNode"
                  },
                  "enabled": {
                    "type": "boolean"
                  }
                }
              },
              "example": {
                "enabled": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated rule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrustRule"
                },
                "example": {
                  "id": "tr_4m8s2k0x9q",
                  "name": "Company laptops",
                  "match": {
                    "op": "and",
                    "children": [
                      {
                        "type": "posture",
                        "field": "computer_type",
                        "operator": "in",
                        "value": [
                          "domain"
                        ]
                      },
                      {
                        "type": "posture",
                        "field": "disk_encrypted",
                        "operator": "eq",
                        "value": true
                      },
                      {
                        "type": "posture",
                        "field": "edr_present",
                        "operator": "eq",
                        "value": true
                      }
                    ]
                  },
                  "enabled": false,
                  "form_representable": true,
                  "form_view": {
                    "include": [],
                    "require": [
                      {
                        "type": "posture",
                        "field": "computer_type",
                        "operator": "in",
                        "value": [
                          "domain"
                        ]
                      },
                      {
                        "type": "posture",
                        "field": "disk_encrypted",
                        "operator": "eq",
                        "value": true
                      },
                      {
                        "type": "posture",
                        "field": "edr_present",
                        "operator": "eq",
                        "value": true
                      }
                    ],
                    "exclude": []
                  },
                  "version": 3,
                  "created_at": "2026-09-20T09:00:00.000Z",
                  "updated_at": "2026-10-13T09:24:11.000Z"
                }
              }
            }
          },
          "400": {
            "description": "`invalid-trust-rule`: The body fails validation; `detail` lists every problem as `path: message`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-trust-rule": {
                    "summary": "The body fails validation; `detail` lists every problem as `path: message`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-trust-rule",
                      "code": "invalid-trust-rule",
                      "title": "invalid trust rule",
                      "status": 400,
                      "detail": "The body fails validation; detail lists every problem as path: message."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`trust-rule-not-found`: No trust rule with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "trust-rule-not-found": {
                    "summary": "No trust rule with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/trust-rule-not-found",
                      "code": "trust-rule-not-found",
                      "title": "trust rule not found",
                      "status": 404,
                      "detail": "No trust rule with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`version-conflict`: `If-Match` does not match the rule's current `version` (someone changed it meanwhile; re-read and retry).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "version-conflict": {
                    "summary": "`If-Match` does not match the rule's current `version` (someone changed it meanwhile; re-read and retry).",
                    "value": {
                      "type": "https://cloudraw.com/problems/version-conflict",
                      "code": "version-conflict",
                      "title": "version conflict",
                      "status": 409,
                      "detail": "If-Match does not match the rule's current version (someone changed it meanwhile; re-read and retry)."
                    }
                  }
                }
              }
            }
          },
          "428": {
            "description": "`if-match-required`: No `If-Match` header was sent.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "if-match-required": {
                    "summary": "No `If-Match` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/if-match-required",
                      "code": "if-match-required",
                      "title": "if match required",
                      "status": 428,
                      "detail": "No If-Match header was sent."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      },
      "delete": {
        "tags": [
          "Device trust"
        ],
        "operationId": "deleteTrustRule",
        "summary": "Delete a trust rule",
        "description": "Deletes the rule and re-evaluates every device right away; devices trusted only through this rule become untrusted. Requires `If-Match`. Audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "rule_id",
            "in": "path",
            "required": true,
            "description": "Trust rule id (from List trust rules).",
            "schema": {
              "type": "string"
            },
            "example": "tr_4m8s2k0x9q"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "description": "The rule's current `version` (from a GET or the last write). Required: without it the call answers `428 if-match-required`; with a stale value `409 version-conflict`.",
            "schema": {
              "type": "string"
            },
            "example": "3"
          }
        ],
        "responses": {
          "202": {
            "description": "Deleted (`state: done`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                },
                "example": {
                  "id": "task_8k2x0m9s1d",
                  "tenant_id": "tq7x2m9k4ab",
                  "state": "done",
                  "result_uri": null,
                  "error": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`trust-rule-not-found`: No trust rule with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "trust-rule-not-found": {
                    "summary": "No trust rule with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/trust-rule-not-found",
                      "code": "trust-rule-not-found",
                      "title": "trust rule not found",
                      "status": 404,
                      "detail": "No trust rule with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`version-conflict`: `If-Match` does not match the rule's current `version` (someone changed it meanwhile; re-read and retry).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "version-conflict": {
                    "summary": "`If-Match` does not match the rule's current `version` (someone changed it meanwhile; re-read and retry).",
                    "value": {
                      "type": "https://cloudraw.com/problems/version-conflict",
                      "code": "version-conflict",
                      "title": "version conflict",
                      "status": 409,
                      "detail": "If-Match does not match the rule's current version (someone changed it meanwhile; re-read and retry)."
                    }
                  }
                }
              }
            }
          },
          "428": {
            "description": "`if-match-required`: No `If-Match` header was sent.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "if-match-required": {
                    "summary": "No `If-Match` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/if-match-required",
                      "code": "if-match-required",
                      "title": "if match required",
                      "status": 428,
                      "detail": "No If-Match header was sent."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/update-check": {
      "get": {
        "tags": [
          "Connector updates"
        ],
        "operationId": "checkClientUpdate",
        "summary": "Check a Cloudraw Connect app update",
        "description": "Answers, for a Cloudraw Connect app at `current_version`, whether it should update, to which version and when, under the workspace policy and the security floor. Handy to see what your users' apps will do. Changes nothing.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "current_version",
            "in": "query",
            "required": false,
            "description": "App version to check (default `0.0.0`).",
            "schema": {
              "type": "string"
            },
            "example": "0.4.6"
          }
        ],
        "responses": {
          "200": {
            "description": "The decision.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdateCheck"
                },
                "example": {
                  "current_version": "0.4.6",
                  "available_version": "0.4.9",
                  "update_available": true,
                  "should_update": true,
                  "when": "window",
                  "deadline": null,
                  "forced": false,
                  "reason": null,
                  "mode": "auto_window",
                  "channel": "stable",
                  "maintenance_window": {
                    "days": [
                      0,
                      1,
                      2,
                      3,
                      4
                    ],
                    "start": "02:00",
                    "end": "05:00",
                    "timezone": "Asia/Jerusalem"
                  },
                  "allow_user_defer": true,
                  "max_defers": 3
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/update-policy": {
      "get": {
        "tags": [
          "Connector updates"
        ],
        "operationId": "getUpdatePolicy",
        "summary": "Get the update policy",
        "description": "Returns the workspace update policy. `mode` and `maintenance_window` decide when connectors (and the Cloudraw Connect app) update; `channel`, `target_version` and the defer settings apply to the Cloudraw Connect app. `security_floor` is set by Cloudraw for critical fixes.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "responses": {
          "200": {
            "description": "The policy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdatePolicy"
                },
                "example": {
                  "mode": "auto_window",
                  "channel": "stable",
                  "maintenance_window": {
                    "days": [
                      0,
                      1,
                      2,
                      3,
                      4
                    ],
                    "start": "02:00",
                    "end": "05:00",
                    "timezone": "Asia/Jerusalem"
                  },
                  "allow_user_defer": true,
                  "max_defers": 3,
                  "target_version": null,
                  "connector_mode": null,
                  "security_floor": {
                    "min_version": null,
                    "grace_hours": 72,
                    "reason": null
                  },
                  "updated_at": "2026-10-13T09:24:11.000Z",
                  "updated_by": "dana.levi@example.com"
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      },
      "put": {
        "tags": [
          "Connector updates"
        ],
        "operationId": "setUpdatePolicy",
        "summary": "Change the update policy",
        "description": "Changes the update policy. Send only the fields you want to change; the others keep their value (inside `maintenance_window` too). Invalid values are refused, never silently dropped. The security floor cannot be changed here. Audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mode": {
                    "type": "string",
                    "enum": [
                      "auto_window",
                      "manual",
                      "immediate"
                    ]
                  },
                  "channel": {
                    "type": "string",
                    "enum": [
                      "stable",
                      "beta"
                    ]
                  },
                  "maintenance_window": {
                    "type": "object",
                    "properties": {
                      "days": {
                        "type": "array",
                        "items": {
                          "type": "integer",
                          "minimum": 0,
                          "maximum": 6
                        },
                        "description": "Non-empty; 0 = Sunday."
                      },
                      "start": {
                        "type": "string",
                        "description": "HH:MM"
                      },
                      "end": {
                        "type": "string",
                        "description": "HH:MM"
                      },
                      "timezone": {
                        "type": "string",
                        "description": "IANA time zone."
                      }
                    },
                    "description": "Any of its fields."
                  },
                  "allow_user_defer": {
                    "type": "boolean"
                  },
                  "max_defers": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 20
                  },
                  "target_version": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Pin the app version (up to 20 characters); null or empty = latest on the channel."
                  },
                  "connector_mode": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "enum": [
                      "auto_window",
                      "manual",
                      "immediate",
                      null
                    ],
                    "description": "Connectors only; null = same as `mode`."
                  }
                }
              },
              "example": {
                "mode": "auto_window",
                "maintenance_window": {
                  "days": [
                    5,
                    6
                  ],
                  "start": "22:00",
                  "end": "04:00",
                  "timezone": "Asia/Jerusalem"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated policy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdatePolicy"
                },
                "example": {
                  "mode": "auto_window",
                  "channel": "stable",
                  "maintenance_window": {
                    "days": [
                      5,
                      6
                    ],
                    "start": "22:00",
                    "end": "04:00",
                    "timezone": "Asia/Jerusalem"
                  },
                  "allow_user_defer": true,
                  "max_defers": 3,
                  "target_version": null,
                  "connector_mode": null,
                  "security_floor": {
                    "min_version": null,
                    "grace_hours": 72,
                    "reason": null
                  },
                  "updated_at": "2026-10-13T09:24:11.000Z",
                  "updated_by": "dana.levi@example.com"
                }
              }
            }
          },
          "400": {
            "description": "`invalid-mode`: `mode` is not auto_window, manual or immediate.\n\n`invalid-connector-mode`: `connector_mode` is not null, auto_window, manual or immediate.\n\n`invalid-channel`: `channel` is not stable or beta.\n\n`invalid-max-defers`: `max_defers` is not an integer 0-20.\n\n`invalid-window-days`: `maintenance_window.days` is empty or holds something other than integers 0-6.\n\n`invalid-window-start`: `maintenance_window.start` is not HH:MM (24 h).\n\n`invalid-window-end`: `maintenance_window.end` is not HH:MM (24 h).\n\n`invalid-window-timezone`: `maintenance_window.timezone` is not an IANA time zone name.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-mode": {
                    "summary": "`mode` is not auto_window, manual or immediate.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-mode",
                      "code": "invalid-mode",
                      "title": "invalid mode",
                      "status": 400,
                      "detail": "mode is not auto_window, manual or immediate."
                    }
                  },
                  "invalid-connector-mode": {
                    "summary": "`connector_mode` is not null, auto_window, manual or immediate.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-connector-mode",
                      "code": "invalid-connector-mode",
                      "title": "invalid connector mode",
                      "status": 400,
                      "detail": "connector_mode is not null, auto_window, manual or immediate."
                    }
                  },
                  "invalid-channel": {
                    "summary": "`channel` is not stable or beta.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-channel",
                      "code": "invalid-channel",
                      "title": "invalid channel",
                      "status": 400,
                      "detail": "channel is not stable or beta."
                    }
                  },
                  "invalid-max-defers": {
                    "summary": "`max_defers` is not an integer 0-20.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-max-defers",
                      "code": "invalid-max-defers",
                      "title": "invalid max defers",
                      "status": 400,
                      "detail": "max_defers is not an integer 0-20."
                    }
                  },
                  "invalid-window-days": {
                    "summary": "`maintenance_window.days` is empty or holds something other than integers 0-6.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-window-days",
                      "code": "invalid-window-days",
                      "title": "invalid window days",
                      "status": 400,
                      "detail": "maintenance_window.days is empty or holds something other than integers 0-6."
                    }
                  },
                  "invalid-window-start": {
                    "summary": "`maintenance_window.start` is not HH:MM (24 h).",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-window-start",
                      "code": "invalid-window-start",
                      "title": "invalid window start",
                      "status": 400,
                      "detail": "maintenance_window.start is not HH:MM (24 h)."
                    }
                  },
                  "invalid-window-end": {
                    "summary": "`maintenance_window.end` is not HH:MM (24 h).",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-window-end",
                      "code": "invalid-window-end",
                      "title": "invalid window end",
                      "status": 400,
                      "detail": "maintenance_window.end is not HH:MM (24 h)."
                    }
                  },
                  "invalid-window-timezone": {
                    "summary": "`maintenance_window.timezone` is not an IANA time zone name.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-window-timezone",
                      "code": "invalid-window-timezone",
                      "title": "invalid window timezone",
                      "status": 400,
                      "detail": "maintenance_window.timezone is not an IANA time zone name."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/usage": {
      "get": {
        "tags": [
          "Workspace"
        ],
        "operationId": "getWorkspaceUsage",
        "summary": "Get monthly usage",
        "description": "What the workspace used in one month: peak and average seats, monthly active users, devices, connectors, apps, private networks, recording and audit log storage, sign-in SMS, remote assist, protected file scans, web filtering and bandwidth (a lower bound from connector reports, not a meter).Cloudraw measures every hour and keeps one row per day; when a month is over it is closed into final figures (`state: closed`). The current month is answered with the figures so far (`state: open`). These are the numbers your invoice is based on.\n\n**Token:** read-only or full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "month",
            "in": "query",
            "required": false,
            "description": "Month, `YYYY-MM` (UTC). Default: the current month.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{4}-(0[1-9]|1[0-2])$"
            },
            "example": "2026-09"
          },
          {
            "name": "daily",
            "in": "query",
            "required": false,
            "description": "`1` adds the day rows of the month (`daily`).",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The month.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkspaceUsage"
                },
                "example": {
                  "tenant_id": "tq7x2m9k4ab",
                  "month": "2026-09",
                  "state": "closed",
                  "closed_at": "2026-10-01T06:00:12.000Z",
                  "close_runs": 1,
                  "days_sampled": 30,
                  "days_in_month": 30,
                  "first_day": "2026-09-01",
                  "last_day": "2026-09-30",
                  "seats_peak": 48,
                  "seats_avg": 46.2,
                  "seats_last": 47,
                  "active_users": 41,
                  "active_users_peak_day": 33,
                  "devices_peak": 61,
                  "devices_last": 60,
                  "connectors_peak": 2,
                  "connectors_last": 2,
                  "connections_peak": 9,
                  "connections_last": 9,
                  "private_networks_peak": 1,
                  "private_networks_last": 1,
                  "recording_gb_max": 18.4,
                  "recording_gb_avg": 15.9,
                  "recording_count_max": 812,
                  "audit_gb_max": 0.21,
                  "audit_gb_avg": 0.18,
                  "sms_sent": 130,
                  "sms_failed": 2,
                  "remote_assist_sessions": 14,
                  "remote_assist_minutes": 236,
                  "remote_assist_technicians": 3,
                  "file_scans_total": 5230,
                  "file_scans": {
                    "ok": 5190,
                    "blocked": 31,
                    "quarantined": 2,
                    "held": 1,
                    "denied": 6,
                    "error": 0
                  },
                  "web_filter_devices_peak": 55,
                  "web_filter_devices_last": 55,
                  "secure_browser_hours": 0,
                  "secure_browser_metered": false,
                  "bandwidth_bytes_lower_bound": 110269022468,
                  "bandwidth_in_bytes_lower_bound": 98234511234,
                  "bandwidth_out_bytes_lower_bound": 12034511234,
                  "bandwidth_source": "connector_session_reports",
                  "bandwidth_label": "lower bound, from connector reports"
                }
              }
            }
          },
          "400": {
            "description": "`invalid-month`: `month` is not `YYYY-MM` with a month from 01 to 12.\n\n`month-in-future`: `month` has not started yet.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid-month": {
                    "summary": "`month` is not `YYYY-MM` with a month from 01 to 12.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-month",
                      "code": "invalid-month",
                      "title": "invalid month",
                      "status": 400,
                      "detail": "month is not YYYY-MM with a month from 01 to 12."
                    }
                  },
                  "month-in-future": {
                    "summary": "`month` has not started yet.",
                    "value": {
                      "type": "https://cloudraw.com/problems/month-in-future",
                      "code": "month-in-future",
                      "title": "month in future",
                      "status": 400,
                      "detail": "month has not started yet."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`usage-unavailable`: Usage figures cannot be read right now. Retry in a minute.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "usage-unavailable": {
                    "summary": "Usage figures cannot be read right now. Retry in a minute.",
                    "value": {
                      "type": "https://cloudraw.com/problems/usage-unavailable",
                      "code": "usage-unavailable",
                      "title": "usage unavailable",
                      "status": 503,
                      "detail": "Usage figures cannot be read right now. Retry in a minute."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/webhooks": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "listWebhooks",
        "summary": "List webhooks",
        "description": "Returns your webhooks and the categories a webhook can subscribe to. Signing secrets are never returned (`has_secret` only). See the `WebhookDelivery` schema for what Cloudraw sends.\n\n**Token:** read-only or full access · **Created by:** owner or security admin",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          }
        ],
        "responses": {
          "200": {
            "description": "The webhooks.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookList"
                },
                "example": {
                  "items": [
                    {
                      "id": "wh_8d2k0s9x1m",
                      "url": "https://hooks.example.com/cloudraw",
                      "events": [
                        "security",
                        "connector"
                      ],
                      "active": true,
                      "has_secret": true,
                      "created_at": "2026-10-13T09:24:11.000Z",
                      "last_delivery": null
                    }
                  ],
                  "events": [
                    "security",
                    "connector",
                    "device",
                    "access",
                    "jit",
                    "all"
                  ],
                  "next_page": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "read-only",
            "full"
          ],
          "roles": [
            "owner",
            "security_admin"
          ]
        }
      },
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "createWebhook",
        "summary": "Create a webhook",
        "description": "Registers an HTTPS endpoint that receives a signed JSON POST for each event in the subscribed categories (see the `WebhookDelivery` schema for the body and signature headers). The URL must be `https://`, a public host (no private, loopback or link-local addresses, no internal names), without credentials, on port 443 or another allowed port (8088, 8443). The answer carries the signing secret (`whsec_…`) **once** — store it; it cannot be read back, only rotated. The webhook starts active. Audited.\n\n**Token:** full access · **Created by:** owner\n\n**Idempotency:** send `Idempotency-Key`. The answer carries a secret shown once: a retry with the same key answers `409 already-issued` instead of the secret.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "Receiver URL, https only, up to 400 characters.",
                    "format": "uri"
                  },
                  "events": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "security",
                        "connector",
                        "device",
                        "access",
                        "jit",
                        "all"
                      ]
                    },
                    "description": "At least one category (duplicates are removed). `all` = every event."
                  }
                },
                "required": [
                  "url",
                  "events"
                ]
              },
              "example": {
                "url": "https://hooks.example.com/cloudraw",
                "events": [
                  "security",
                  "connector"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The webhook, with its signing secret (shown once).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookWithSecret"
                },
                "example": {
                  "id": "wh_8d2k0s9x1m",
                  "url": "https://hooks.example.com/cloudraw",
                  "events": [
                    "security",
                    "connector"
                  ],
                  "active": true,
                  "has_secret": true,
                  "created_at": "2026-10-13T09:24:11.000Z",
                  "last_delivery": null,
                  "secret": "whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
                }
              }
            }
          },
          "400": {
            "description": "`https-url-required`: `url` is missing or does not start with `https://`.\n\n`invalid-webhook-url`: The URL is not allowed (private or internal host, credentials in the URL, port not allowed); `detail` says why.\n\n`events-required`: `events` is missing or empty.\n\n`unknown-event`: `events` contains a category that is not in the list.\n\n`category-not-available-yet`: `events` contains `audit` or `billing`, which webhooks do not send yet.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "https-url-required": {
                    "summary": "`url` is missing or does not start with `https://`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/https-url-required",
                      "code": "https-url-required",
                      "title": "https url required",
                      "status": 400,
                      "detail": "url is missing or does not start with https://."
                    }
                  },
                  "invalid-webhook-url": {
                    "summary": "The URL is not allowed (private or internal host, credentials in the URL, port not allowed); `detail` says why.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-webhook-url",
                      "code": "invalid-webhook-url",
                      "title": "invalid webhook url",
                      "status": 400,
                      "detail": "The URL is not allowed (private or internal host, credentials in the URL, port not allowed); detail says why."
                    }
                  },
                  "events-required": {
                    "summary": "`events` is missing or empty.",
                    "value": {
                      "type": "https://cloudraw.com/problems/events-required",
                      "code": "events-required",
                      "title": "events required",
                      "status": 400,
                      "detail": "events is missing or empty."
                    }
                  },
                  "unknown-event": {
                    "summary": "`events` contains a category that is not in the list.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unknown-event",
                      "code": "unknown-event",
                      "title": "unknown event",
                      "status": 400,
                      "detail": "events contains a category that is not in the list."
                    }
                  },
                  "category-not-available-yet": {
                    "summary": "`events` contains `audit` or `billing`, which webhooks do not send yet.",
                    "value": {
                      "type": "https://cloudraw.com/problems/category-not-available-yet",
                      "code": "category-not-available-yet",
                      "title": "category not available yet",
                      "status": 400,
                      "detail": "events contains audit or billing, which webhooks do not send yet."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`idempotency-key-reuse`: The same `Idempotency-Key` was used with a different body within 24 hours.\n\n`already-issued`: This `Idempotency-Key` already created a secret; it is shown only once. Retry with a new key.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "idempotency-key-reuse": {
                    "summary": "The same `Idempotency-Key` was used with a different body within 24 hours.",
                    "value": {
                      "type": "https://cloudraw.com/problems/idempotency-key-reuse",
                      "code": "idempotency-key-reuse",
                      "title": "idempotency key reuse",
                      "status": 409,
                      "detail": "The same Idempotency-Key was used with a different body within 24 hours."
                    }
                  },
                  "already-issued": {
                    "summary": "This `Idempotency-Key` already created a secret; it is shown only once. Retry with a new key.",
                    "value": {
                      "type": "https://cloudraw.com/problems/already-issued",
                      "code": "already-issued",
                      "title": "already issued",
                      "status": 409,
                      "detail": "This Idempotency-Key already created a secret; it is shown only once. Retry with a new key."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`secret-storage-unavailable`: Secrets cannot be stored safely right now. Retry later.\n\n`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "secret-storage-unavailable": {
                    "summary": "Secrets cannot be stored safely right now. Retry later.",
                    "value": {
                      "type": "https://cloudraw.com/problems/secret-storage-unavailable",
                      "code": "secret-storage-unavailable",
                      "title": "secret storage unavailable",
                      "status": 503,
                      "detail": "Secrets cannot be stored safely right now. Retry later."
                    }
                  },
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        },
        "x-cloudraw-idempotent": "secret"
      }
    },
    "/v0/tenants/{tenant_id}/webhooks/{webhook_id}": {
      "patch": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "updateWebhook",
        "summary": "Update a webhook",
        "description": "Changes the subscribed categories and/or pauses (`active: false`) or resumes the webhook. The URL cannot be changed: delete the webhook and create a new one, so a new destination always gets a new signing secret. Audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "webhook_id",
            "in": "path",
            "required": true,
            "description": "Webhook id.",
            "schema": {
              "type": "string"
            },
            "example": "wh_8d2k0s9x1m"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "events": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "security",
                        "connector",
                        "device",
                        "access",
                        "jit",
                        "all"
                      ]
                    },
                    "description": "Replaces the subscription; at least one category."
                  },
                  "active": {
                    "type": "boolean",
                    "description": "False pauses deliveries."
                  }
                }
              },
              "example": {
                "events": [
                  "security",
                  "connector",
                  "device"
                ],
                "active": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated webhook.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                },
                "example": {
                  "id": "wh_8d2k0s9x1m",
                  "url": "https://hooks.example.com/cloudraw",
                  "events": [
                    "security",
                    "connector",
                    "device"
                  ],
                  "active": true,
                  "has_secret": true,
                  "created_at": "2026-10-13T09:24:11.000Z",
                  "last_delivery": null
                }
              }
            }
          },
          "400": {
            "description": "`url-is-not-editable`: The body contains `url`.\n\n`events-required`: `events` is present but empty or not a list.\n\n`unknown-event`: `events` contains a category that is not in the list.\n\n`category-not-available-yet`: `events` contains `audit` or `billing`, which webhooks do not send yet.\n\n`active-must-be-boolean`: `active` is not true or false.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "url-is-not-editable": {
                    "summary": "The body contains `url`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/url-is-not-editable",
                      "code": "url-is-not-editable",
                      "title": "url is not editable",
                      "status": 400,
                      "detail": "The body contains url."
                    }
                  },
                  "events-required": {
                    "summary": "`events` is present but empty or not a list.",
                    "value": {
                      "type": "https://cloudraw.com/problems/events-required",
                      "code": "events-required",
                      "title": "events required",
                      "status": 400,
                      "detail": "events is present but empty or not a list."
                    }
                  },
                  "unknown-event": {
                    "summary": "`events` contains a category that is not in the list.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unknown-event",
                      "code": "unknown-event",
                      "title": "unknown event",
                      "status": 400,
                      "detail": "events contains a category that is not in the list."
                    }
                  },
                  "category-not-available-yet": {
                    "summary": "`events` contains `audit` or `billing`, which webhooks do not send yet.",
                    "value": {
                      "type": "https://cloudraw.com/problems/category-not-available-yet",
                      "code": "category-not-available-yet",
                      "title": "category not available yet",
                      "status": 400,
                      "detail": "events contains audit or billing, which webhooks do not send yet."
                    }
                  },
                  "active-must-be-boolean": {
                    "summary": "`active` is not true or false.",
                    "value": {
                      "type": "https://cloudraw.com/problems/active-must-be-boolean",
                      "code": "active-must-be-boolean",
                      "title": "active must be boolean",
                      "status": 400,
                      "detail": "active is not true or false."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`webhook-not-found`: No webhook with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "webhook-not-found": {
                    "summary": "No webhook with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/webhook-not-found",
                      "code": "webhook-not-found",
                      "title": "webhook not found",
                      "status": 404,
                      "detail": "No webhook with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      },
      "delete": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "deleteWebhook",
        "summary": "Delete a webhook",
        "description": "Removes the webhook. Deliveries still queued for it stop at once. Audited.\n\n**Token:** full access · **Created by:** owner",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "webhook_id",
            "in": "path",
            "required": true,
            "description": "Webhook id.",
            "schema": {
              "type": "string"
            },
            "example": "wh_8d2k0s9x1m"
          }
        ],
        "responses": {
          "202": {
            "description": "Done (the task is already complete).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                },
                "example": {
                  "id": "task_8s2k0x9m1d",
                  "tenant_id": "tq7x2m9k4ab",
                  "state": "done",
                  "result_uri": null,
                  "error": null
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`webhook-not-found`: No webhook with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "webhook-not-found": {
                    "summary": "No webhook with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/webhook-not-found",
                      "code": "webhook-not-found",
                      "title": "webhook not found",
                      "status": 404,
                      "detail": "No webhook with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        }
      }
    },
    "/v0/tenants/{tenant_id}/webhooks/{webhook_id}/rotate-secret": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "rotateWebhookSecret",
        "summary": "Rotate a webhook signing secret",
        "description": "Issues a new signing secret, returned **once** in this answer. The old secret stops signing immediately — every delivery after this call (including retries of queued events) is signed with the new one, so update your receiver right away. Audited.\n\n**Token:** full access · **Created by:** owner\n\n**Idempotency:** send `Idempotency-Key`. The answer carries a secret shown once: a retry with the same key answers `409 already-issued` instead of the secret.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "webhook_id",
            "in": "path",
            "required": true,
            "description": "Webhook id.",
            "schema": {
              "type": "string"
            },
            "example": "wh_8d2k0s9x1m"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "The webhook with its new signing secret (shown once).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookWithSecret"
                },
                "example": {
                  "id": "wh_8d2k0s9x1m",
                  "url": "https://hooks.example.com/cloudraw",
                  "events": [
                    "security",
                    "connector"
                  ],
                  "active": true,
                  "has_secret": true,
                  "created_at": "2026-10-13T09:24:11.000Z",
                  "last_delivery": null,
                  "secret": "whsec_yyyyyyyyyyyyyyyyyyyyyyyyyyyy"
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`webhook-not-found`: No webhook with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "webhook-not-found": {
                    "summary": "No webhook with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/webhook-not-found",
                      "code": "webhook-not-found",
                      "title": "webhook not found",
                      "status": 404,
                      "detail": "No webhook with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`idempotency-key-reuse`: The same `Idempotency-Key` was used with a different body within 24 hours.\n\n`already-issued`: This `Idempotency-Key` already created a secret; it is shown only once. Retry with a new key.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "idempotency-key-reuse": {
                    "summary": "The same `Idempotency-Key` was used with a different body within 24 hours.",
                    "value": {
                      "type": "https://cloudraw.com/problems/idempotency-key-reuse",
                      "code": "idempotency-key-reuse",
                      "title": "idempotency key reuse",
                      "status": 409,
                      "detail": "The same Idempotency-Key was used with a different body within 24 hours."
                    }
                  },
                  "already-issued": {
                    "summary": "This `Idempotency-Key` already created a secret; it is shown only once. Retry with a new key.",
                    "value": {
                      "type": "https://cloudraw.com/problems/already-issued",
                      "code": "already-issued",
                      "title": "already issued",
                      "status": 409,
                      "detail": "This Idempotency-Key already created a secret; it is shown only once. Retry with a new key."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`secret-storage-unavailable`: Secrets cannot be stored safely right now. Retry later.\n\n`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "secret-storage-unavailable": {
                    "summary": "Secrets cannot be stored safely right now. Retry later.",
                    "value": {
                      "type": "https://cloudraw.com/problems/secret-storage-unavailable",
                      "code": "secret-storage-unavailable",
                      "title": "secret storage unavailable",
                      "status": 503,
                      "detail": "Secrets cannot be stored safely right now. Retry later."
                    }
                  },
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        },
        "x-cloudraw-idempotent": "secret"
      }
    },
    "/v0/tenants/{tenant_id}/webhooks/{webhook_id}/test": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "testWebhook",
        "summary": "Send a test event",
        "description": "Sends one real, signed test event (category `system`, action `webhook.test`) to the webhook now and reports your receiver's answer — no retries. Works on paused webhooks too. The result is saved as `last_delivery`. Audited.\n\n**Token:** full access · **Created by:** owner\n\n**Rate limit:** 10 test events per hour per webhook.",
        "security": [
          {
            "apiToken": []
          }
        ],
        "parameters": [
          {
            "name": "tenant_id",
            "in": "path",
            "required": true,
            "description": "Your workspace id (Settings → Workspace in the console; it is also in every console URL).",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]{4,40}$"
            },
            "example": "tq7x2m9k4ab"
          },
          {
            "name": "webhook_id",
            "in": "path",
            "required": true,
            "description": "Webhook id.",
            "schema": {
              "type": "string"
            },
            "example": "wh_8d2k0s9x1m"
          }
        ],
        "responses": {
          "200": {
            "description": "What the receiver answered.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "delivered": {
                      "type": "boolean",
                      "description": "The receiver answered 2xx."
                    },
                    "last_delivery": {
                      "type": "object",
                      "properties": {
                        "at": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "ok": {
                          "type": "boolean"
                        },
                        "code": {
                          "type": "integer",
                          "description": "HTTP status your receiver answered (0 when it did not answer)."
                        },
                        "error": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "test": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "at",
                        "ok"
                      ]
                    }
                  },
                  "required": [
                    "delivered",
                    "last_delivery"
                  ]
                },
                "example": {
                  "delivered": false,
                  "last_delivery": {
                    "at": "2026-10-13T09:24:11.000Z",
                    "ok": false,
                    "code": 401,
                    "error": "HTTP 401",
                    "test": true
                  }
                }
              }
            }
          },
          "401": {
            "description": "`unauthorized`: No `Authorization: Bearer crw_…` header was sent.\n\n`invalid-token`: The token is unknown or was revoked.\n\n`token-expired`: The token is past its expiry date. Create a new one.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "unauthorized": {
                    "summary": "No `Authorization: Bearer crw_…` header was sent.",
                    "value": {
                      "type": "https://cloudraw.com/problems/unauthorized",
                      "code": "unauthorized",
                      "title": "unauthorized",
                      "status": 401,
                      "detail": "No Authorization: Bearer crw_… header was sent."
                    }
                  },
                  "invalid-token": {
                    "summary": "The token is unknown or was revoked.",
                    "value": {
                      "type": "https://cloudraw.com/problems/invalid-token",
                      "code": "invalid-token",
                      "title": "invalid token",
                      "status": 401,
                      "detail": "The token is unknown or was revoked."
                    }
                  },
                  "token-expired": {
                    "summary": "The token is past its expiry date. Create a new one.",
                    "value": {
                      "type": "https://cloudraw.com/problems/token-expired",
                      "code": "token-expired",
                      "title": "token expired",
                      "status": 401,
                      "detail": "The token is past its expiry date. Create a new one."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`insufficient-scope`: The token is read-only and this call changes something.\n\n`insufficient-role`: The token's role ceiling does not allow this call.\n\n`tenant-assertion-mismatch`: The token belongs to another workspace than `{tenant_id}`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "insufficient-scope": {
                    "summary": "The token is read-only and this call changes something.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-scope",
                      "code": "insufficient-scope",
                      "title": "insufficient scope",
                      "status": 403,
                      "detail": "The token is read-only and this call changes something."
                    }
                  },
                  "insufficient-role": {
                    "summary": "The token's role ceiling does not allow this call.",
                    "value": {
                      "type": "https://cloudraw.com/problems/insufficient-role",
                      "code": "insufficient-role",
                      "title": "insufficient role",
                      "status": 403,
                      "detail": "The token's role ceiling does not allow this call."
                    }
                  },
                  "tenant-assertion-mismatch": {
                    "summary": "The token belongs to another workspace than `{tenant_id}`.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-assertion-mismatch",
                      "code": "tenant-assertion-mismatch",
                      "title": "tenant assertion mismatch",
                      "status": 403,
                      "detail": "The token belongs to another workspace than {tenant_id}."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`webhook-not-found`: No webhook with this id.\n\n`tenant-not-found`: No workspace with this id.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "webhook-not-found": {
                    "summary": "No webhook with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/webhook-not-found",
                      "code": "webhook-not-found",
                      "title": "webhook not found",
                      "status": 404,
                      "detail": "No webhook with this id."
                    }
                  },
                  "tenant-not-found": {
                    "summary": "No workspace with this id.",
                    "value": {
                      "type": "https://cloudraw.com/problems/tenant-not-found",
                      "code": "tenant-not-found",
                      "title": "tenant not found",
                      "status": 404,
                      "detail": "No workspace with this id."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`test-rate-limited`: More than 10 test events for this webhook this hour.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "test-rate-limited": {
                    "summary": "More than 10 test events for this webhook this hour.",
                    "value": {
                      "type": "https://cloudraw.com/problems/test-rate-limited",
                      "code": "test-rate-limited",
                      "title": "test rate limited",
                      "status": 429,
                      "detail": "More than 10 test events for this webhook this hour."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`test-failed`: The test could not be sent; `detail` says why.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "test-failed": {
                    "summary": "The test could not be sent; `detail` says why.",
                    "value": {
                      "type": "https://cloudraw.com/problems/test-failed",
                      "code": "test-failed",
                      "title": "test failed",
                      "status": 500,
                      "detail": "The test could not be sent; detail says why."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`busy`: Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "busy": {
                    "summary": "Cloudraw is switching servers or cannot save right now. Retry after `Retry-After` seconds.",
                    "value": {
                      "type": "https://cloudraw.com/problems/busy",
                      "code": "busy",
                      "title": "busy",
                      "status": 503,
                      "detail": "Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "x-cloudraw-access": {
          "scopes": [
            "full"
          ],
          "roles": [
            "owner"
          ]
        },
        "x-cloudraw-rate-limit": "10 test events per hour per webhook."
      }
    }
  },
  "webhooks": {
    "cloudrawEvent": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Event delivered to your webhook URL",
        "operationId": "receiveWebhookEvent",
        "description": "The JSON body Cloudraw POSTs to your webhook URL (`Content-Type: application/json`, `User-Agent: cloudraw-notify/1`).\n\n**Signature headers** (sent when the webhook has a signing secret — every webhook created through the API has one):\n- `X-Cloudraw-Signature: sha256=<hex>` — HMAC-SHA256 of the raw body with your signing secret (v0, kept for older receivers).\n- `X-Cloudraw-Timestamp: <unix seconds>` — time of this delivery attempt.\n- `X-Cloudraw-Signature-V1: sha256=<hex>` — HMAC-SHA256 of `<timestamp>.<raw body>` with your signing secret. Verify this one, and reject the request when the timestamp is more than 300 seconds from your clock.\n\nCompute the HMAC over the exact bytes you received (before parsing JSON) and compare in constant time.\n\n**Delivery:** answer with any 2xx within about 8 seconds (15 seconds total). Anything else is retried after 5 s, 30 s, 2 min, 10 min and 30 min (6 attempts in all), then dropped. Retries reuse `id` and `at` but carry a fresh timestamp and signatures. Events are delivered in order per webhook. Alerts dismissed by a suppression rule are not sent.\n\n**Subscriptions** (`events` on the webhook): `security`, `connector`, `device`, `access`, `jit`, `all`. `connector` = connector health; `device` = device trust changes; `jit` = just-in-time access requests and grants; `all` = every event, including `system`, `files`, `app_firewall` and `support` events, which have no category of their own. `audit` and `billing` are not available yet: a subscription to them is refused (`400 category-not-available-yet`); stream the audit log to a SIEM instead (Log streaming). Webhooks created before 13 Oct 2026 with those categories keep working for their other categories; the two are left out of `events` in every answer.",
        "parameters": [
          {
            "name": "X-Cloudraw-Signature",
            "in": "header",
            "required": false,
            "description": "`sha256=` + hex HMAC-SHA256(secret, raw body). v0, kept for older receivers.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Cloudraw-Timestamp",
            "in": "header",
            "required": false,
            "description": "Unix seconds of this delivery attempt.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Cloudraw-Signature-V1",
            "in": "header",
            "required": false,
            "description": "`sha256=` + hex HMAC-SHA256(secret, `<timestamp>.<raw body>`). Verify this; reject if the timestamp is more than 300 s off.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookDelivery"
              },
              "example": {
                "id": "evt_6k2m9x0s8d1q",
                "tenant": "tq7x2m9k4ab",
                "category": "security",
                "at": "2026-10-13T09:24:11.000Z",
                "event": {
                  "action": "security_event",
                  "severity": "bad",
                  "message": "Blocked: Port scan from unmanaged device",
                  "data": {
                    "event": "sev_9x2k0m8s1d"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the event; anything else (or no answer within about 8 s) is retried."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiToken": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "crw_…",
        "description": "A workspace API token. Create one in the Cloudraw console: **Settings → API → Create token**. A token is shown once; store it in a secret manager. Read-only tokens can call every GET; full-access tokens (created by an owner) can also change things. A token never has more power than the admin who created it, expires (default 90 days, at most 365) and can be revoked at any time on the same page."
      }
    },
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "A unique value (e.g. a UUID) per logical operation. Retrying with the same key and body within 24 hours returns the first answer instead of doing the work twice.",
        "schema": {
          "type": "string",
          "maxLength": 200
        },
        "example": "6f1c2b9e-3d4a-4c1e-9b8f-0a7d5e2c1b3f"
      }
    },
    "headers": {
      "RetryAfter": {
        "description": "Seconds to wait before retrying.",
        "schema": {
          "type": "integer"
        },
        "example": 30
      }
    },
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 (7807) problem details. Switch on `code`; it never changes for a given error. `title` and `detail` are for people.",
        "properties": {
          "type": {
            "type": "string",
            "format": "uri",
            "description": "`https://cloudraw.com/problems/<code>`"
          },
          "code": {
            "type": "string",
            "description": "Stable machine-readable error code, e.g. `person-not-found`."
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": [
              "string",
              "null"
            ]
          },
          "retry_after_s": {
            "type": "integer",
            "description": "On 429 and 503: seconds to wait (same value as the `Retry-After` header)."
          },
          "errors": {
            "type": "array",
            "description": "Field-level details for validation errors.",
            "items": {
              "type": "object",
              "properties": {
                "path": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        },
        "required": [
          "type",
          "code",
          "title",
          "status"
        ],
        "example": {
          "type": "https://cloudraw.com/problems/person-not-found",
          "code": "person-not-found",
          "title": "person not found",
          "status": 404,
          "detail": null
        }
      },
      "Task": {
        "type": "object",
        "description": "Answer of an accepted (202) request. `state` is `done` when the change already happened.",
        "properties": {
          "id": {
            "type": "string"
          },
          "tenant_id": {
            "type": "string"
          },
          "state": {
            "type": "string",
            "enum": [
              "pending",
              "running",
              "done",
              "failed"
            ]
          },
          "result_uri": {
            "type": [
              "string",
              "null"
            ]
          },
          "error": {
            "type": [
              "object",
              "string",
              "null"
            ],
            "description": "Why it failed, or a short status note (e.g. `revoke_pending`)."
          }
        },
        "required": [
          "id",
          "state"
        ]
      },
      "Workspace": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Workspace id."
          },
          "name": {
            "type": "string",
            "description": "Display name, 1-80 characters."
          },
          "tier": {
            "type": "string",
            "description": "Hosting tier (`shared` for most workspaces)."
          },
          "external_ref": {
            "type": [
              "string",
              "null"
            ],
            "description": "Your own reference for this workspace, if set by Cloudraw at creation."
          },
          "quotas": {
            "type": "object",
            "properties": {
              "max_users": {
                "type": "integer",
                "description": "Seats in the plan."
              },
              "max_devices": {
                "type": "integer"
              },
              "max_connections": {
                "type": "integer"
              },
              "max_connectors": {
                "type": "integer"
              },
              "max_private_networks": {
                "type": "integer"
              }
            },
            "description": "Plan limits. Changed by Cloudraw (billing), not through the API."
          },
          "usage": {
            "type": "object",
            "properties": {
              "users": {
                "type": "integer"
              },
              "devices": {
                "type": "integer"
              },
              "connections": {
                "type": "integer"
              },
              "connectors": {
                "type": "integer"
              },
              "private_networks": {
                "type": "integer"
              }
            },
            "description": "What the workspace uses now."
          },
          "status": {
            "type": "object",
            "properties": {
              "phase": {
                "type": "string",
                "description": "`ready` when the workspace is fully provisioned."
              },
              "observed_at": {
                "type": "string",
                "format": "date-time"
              },
              "message": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "version": {
            "type": "integer",
            "description": "Increases on every change; send it as `If-Match` on PATCH to avoid overwriting a concurrent change."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "name",
          "version"
        ]
      },
      "WorkspaceUsage": {
        "type": "object",
        "properties": {
          "tenant_id": {
            "type": "string",
            "description": "Workspace id."
          },
          "month": {
            "type": "string",
            "description": "`YYYY-MM` (UTC)."
          },
          "state": {
            "type": "string",
            "enum": [
              "open",
              "closed",
              "not_closed"
            ],
            "description": "`open` = the current month, figures so far; `closed` = final figures written at month close; `not_closed` = a past month whose close has not run yet (figures computed from the daily rows)."
          },
          "closed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the month was closed (the latest run)."
          },
          "close_runs": {
            "type": "integer",
            "description": "How many times the month was closed. Closing again recomputes the same figures from the same daily rows."
          },
          "days_sampled": {
            "type": "integer",
            "description": "Days of the month with a measurement."
          },
          "days_in_month": {
            "type": "integer"
          },
          "first_day": {
            "type": [
              "string",
              "null"
            ]
          },
          "last_day": {
            "type": [
              "string",
              "null"
            ]
          },
          "seats_peak": {
            "type": "integer",
            "description": "Highest number of people holding a seat on any day (the plan seat count)."
          },
          "seats_avg": {
            "type": "number",
            "description": "Average seats over the days sampled."
          },
          "seats_last": {
            "type": "integer",
            "description": "Seats on the last day sampled."
          },
          "active_users": {
            "type": "integer",
            "description": "Monthly active users: distinct people who signed in, used an app or had a Cloudraw Connect device online during the month."
          },
          "active_users_peak_day": {
            "type": "integer",
            "description": "Most active people on one day."
          },
          "devices_peak": {
            "type": "integer"
          },
          "devices_last": {
            "type": "integer"
          },
          "connectors_peak": {
            "type": "integer"
          },
          "connectors_last": {
            "type": "integer"
          },
          "connections_peak": {
            "type": "integer",
            "description": "Apps (connections)."
          },
          "connections_last": {
            "type": "integer"
          },
          "private_networks_peak": {
            "type": "integer"
          },
          "private_networks_last": {
            "type": "integer"
          },
          "recording_gb_max": {
            "type": "number",
            "description": "Recording storage, highest day (GB, 10^9 bytes)."
          },
          "recording_gb_avg": {
            "type": "number",
            "description": "Recording storage, average over the days sampled (GB)."
          },
          "recording_count_max": {
            "type": "integer"
          },
          "audit_gb_max": {
            "type": "number",
            "description": "Audit and access log storage, highest day (GB)."
          },
          "audit_gb_avg": {
            "type": "number"
          },
          "sms_sent": {
            "type": "integer",
            "description": "Sign-in SMS codes sent."
          },
          "sms_failed": {
            "type": "integer",
            "description": "Sign-in SMS codes that could not be sent."
          },
          "remote_assist_sessions": {
            "type": "integer",
            "description": "Remote assist sessions requested."
          },
          "remote_assist_minutes": {
            "type": "integer",
            "description": "Minutes of active remote assist."
          },
          "remote_assist_technicians": {
            "type": "integer",
            "description": "Distinct admins who started a remote assist session."
          },
          "file_scans_total": {
            "type": "integer"
          },
          "file_scans": {
            "type": "object",
            "properties": {
              "ok": {
                "type": "integer"
              },
              "blocked": {
                "type": "integer"
              },
              "quarantined": {
                "type": "integer"
              },
              "held": {
                "type": "integer"
              },
              "denied": {
                "type": "integer"
              },
              "error": {
                "type": "integer"
              }
            },
            "description": "Protected file server decisions by outcome (every operation except folder listings)."
          },
          "web_filter_devices_peak": {
            "type": "integer",
            "description": "Devices with web filtering on (module granted, filtering switched on, a profile applied)."
          },
          "web_filter_devices_last": {
            "type": "integer"
          },
          "secure_browser_hours": {
            "type": "number",
            "description": "Secure Browser session hours. 0 until Secure Browser is available (`secure_browser_metered: false`)."
          },
          "secure_browser_metered": {
            "type": "boolean"
          },
          "bandwidth_bytes_lower_bound": {
            "type": "integer",
            "description": "Bytes in both directions that your connectors reported per session. A LOWER BOUND, not a meter: traffic of sessions whose connector does not report bytes is missing, so it is always at or below what your own meters show. Show it with `bandwidth_label` (\"lower bound, from connector reports\")."
          },
          "bandwidth_in_bytes_lower_bound": {
            "type": "integer",
            "description": "Lower bound of bytes from apps to users (connector reports)."
          },
          "bandwidth_out_bytes_lower_bound": {
            "type": "integer",
            "description": "Lower bound of bytes from users to apps (connector reports)."
          },
          "bandwidth_source": {
            "type": "string",
            "enum": [
              "connector_session_reports",
              "overlay_fabric_usage"
            ],
            "description": "`connector_session_reports`: only sessions your connectors report bytes for (a lower bound). `overlay_fabric_usage`: every byte through Cloudraw (coming)."
          },
          "bandwidth_label": {
            "type": "string",
            "description": "Text to show next to the bandwidth figures on any page or invoice: `lower bound, from connector reports`."
          },
          "daily": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "day": {
                  "type": "string",
                  "description": "UTC day, `YYYY-MM-DD`."
                },
                "seats": {
                  "type": "integer"
                },
                "active_users": {
                  "type": "integer"
                },
                "devices": {
                  "type": "integer"
                },
                "connectors": {
                  "type": "integer"
                },
                "connections": {
                  "type": "integer"
                },
                "private_networks": {
                  "type": "integer"
                },
                "recording_bytes": {
                  "type": "integer"
                },
                "recording_count": {
                  "type": "integer"
                },
                "audit_bytes": {
                  "type": "integer"
                },
                "audit_rows": {
                  "type": "integer"
                },
                "sms_sent": {
                  "type": "integer"
                },
                "sms_failed": {
                  "type": "integer"
                },
                "ra_sessions": {
                  "type": "integer"
                },
                "ra_minutes": {
                  "type": "integer"
                },
                "ra_technicians": {
                  "type": "integer"
                },
                "file_scans": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "integer"
                    },
                    "blocked": {
                      "type": "integer"
                    },
                    "quarantined": {
                      "type": "integer"
                    },
                    "held": {
                      "type": "integer"
                    },
                    "denied": {
                      "type": "integer"
                    },
                    "error": {
                      "type": "integer"
                    }
                  },
                  "description": "Protected file server decisions by outcome (every operation except folder listings)."
                },
                "file_scans_total": {
                  "type": "integer"
                },
                "web_filter_devices": {
                  "type": "integer"
                },
                "secure_browser_hours": {
                  "type": "number"
                },
                "bandwidth_bytes_lower_bound": {
                  "type": "integer",
                  "description": "Lower bound, from connector reports."
                },
                "bandwidth_in_bytes_lower_bound": {
                  "type": "integer"
                },
                "bandwidth_out_bytes_lower_bound": {
                  "type": "integer"
                },
                "samples": {
                  "type": "integer",
                  "description": "Measurements taken that day."
                },
                "sampled_at": {
                  "type": "string",
                  "format": "date-time",
                  "description": "Last measurement."
                }
              },
              "required": [
                "day"
              ],
              "description": "One day. Counts of the day: peaks for what exists (seats, devices, storage), totals for what happens (SMS, sessions, scans)."
            },
            "description": "With `daily=1` only: the day rows of the month."
          }
        },
        "required": [
          "tenant_id",
          "month",
          "state"
        ]
      },
      "Person": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Person id."
          },
          "email": {
            "type": "string",
            "description": "E-mail address; unique in the workspace (case-insensitive)."
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Display name."
          },
          "groups": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Ids of the groups this person belongs to. Group membership is what access rules match on."
          },
          "created_by_integrator": {
            "type": [
              "object",
              "null"
            ],
            "description": "Set when an integrator (partner) created this person on your behalf.",
            "properties": {
              "kind": {
                "type": "string"
              },
              "partner_id": {
                "type": "string"
              },
              "partner_name": {
                "type": "string"
              },
              "member": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "member_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "at": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "idp": {
            "type": [
              "string",
              "null"
            ],
            "description": "How the person signs in, as recorded at creation: `cloudraw` (Cloudraw password + e-mail code), `ad`, `sso`, or the value you sent on create."
          },
          "mfa": {
            "type": "boolean",
            "description": "Admin-set MFA flag."
          },
          "suspended": {
            "type": "boolean",
            "description": "Suspended people have no access: their devices lose every grant and their sessions are cut."
          },
          "quarantined": {
            "type": "boolean",
            "description": "Under a security hold (see Quarantine a person)."
          },
          "quarantined_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "quarantine_reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "last_seen": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Latest activity: own sign-in, any of their devices, or a browser portal session."
          },
          "last_seen_via": {
            "type": [
              "string",
              "null"
            ],
            "description": "Where `last_seen` came from: `sign-in`, `portal`, or a device name."
          },
          "device_count": {
            "type": "integer",
            "description": "Enrolled devices linked to this person."
          },
          "state": {
            "type": "string",
            "enum": [
              "pending_approval",
              "suspended",
              "active",
              "invited",
              "not_invited"
            ],
            "description": "`active` = has been seen at least once; `invited` = has a sign-in account but has not signed in yet; `pending_approval` = a self sign-up waiting for an admin."
          },
          "invited_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Last invitation e-mail."
          },
          "invite_count": {
            "type": "integer",
            "description": "Invitations sent so far."
          },
          "ad_groups_synced_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Last refresh of Active Directory groups for this person."
          },
          "files_security": {
            "type": [
              "object",
              "null"
            ],
            "description": "Protected file shares in the last 24 hours: blocked / malware / denied transfers and files waiting in quarantine. Null when nothing happened.",
            "properties": {
              "quarantine_open": {
                "type": "integer"
              },
              "blocked_24h": {
                "type": "integer"
              },
              "malware_24h": {
                "type": "integer"
              },
              "denied_24h": {
                "type": "integer"
              },
              "last": {
                "type": [
                  "object",
                  "null"
                ],
                "description": "The latest such file event."
              }
            }
          },
          "via": {
            "type": [
              "string",
              "null"
            ],
            "description": "How the person was added, e.g. `self-signup`, `join-link`, `bulk-invite`, `sign-in account`; null when created by an admin."
          },
          "requested_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "For self sign-ups and join links: when they asked to join."
          },
          "join_link_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "The join link they used, if any."
          },
          "sign_in": {
            "type": [
              "object",
              "null"
            ],
            "description": "How this person signs in. Null when it cannot be told yet.",
            "properties": {
              "method": {
                "type": "string",
                "description": "`cloudraw`, `ad`, or the identity provider type (e.g. `entra`)."
              },
              "second_factor": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "`email_code`, `provider` (handled by your identity provider) or null."
              },
              "method_source": {
                "type": "string",
                "enum": [
                  "linked",
                  "configured"
                ],
                "description": "`linked` = taken from the person's own sign-in account; `configured` = the workspace setting (not confirmed yet)."
              },
              "linked": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "Only when the workspace uses its own identity provider: whether this person's account is linked to it (null = not checked yet)."
              }
            }
          },
          "idp_links": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "provider": {
                  "type": "string",
                  "description": "Provider type, e.g. `entra` or `ad`."
                },
                "name": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "linked": {
                  "type": [
                    "boolean",
                    "null"
                  ],
                  "description": "null = not checked yet."
                },
                "linked_at": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "date-time"
                }
              }
            },
            "description": "One row per sign-in provider configured for the workspace."
          },
          "idp_links_checked_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "sign_in_conflict": {
            "type": [
              "object",
              "null"
            ],
            "description": "More than one sign-in account uses this e-mail address; an admin must remove the extra one.",
            "properties": {
              "accounts": {
                "type": "integer"
              },
              "since": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "phone_masked": {
            "type": [
              "string",
              "null"
            ],
            "description": "Phone number for SMS sign-in codes, masked."
          },
          "sms_codes": {
            "type": "boolean",
            "description": "The person can receive SMS sign-in codes now."
          },
          "second_factors": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string",
              "enum": [
                "email_code",
                "sms_code",
                "authenticator_app",
                "security_key",
                "passkey"
              ]
            },
            "description": "Second-step methods the person has set up (cached; null = not looked up yet)."
          },
          "second_factors_checked_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "email",
          "groups",
          "state"
        ]
      },
      "PersonList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Person"
            }
          },
          "next_page": {
            "type": "null",
            "description": "Always null: the list is not paginated."
          }
        },
        "required": [
          "items"
        ]
      },
      "PersonUpdated": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Person"
          },
          {
            "type": "object",
            "properties": {
              "sessions_cut": {
                "type": "integer",
                "description": "Only when this call suspended the person: sessions that were cut."
              }
            }
          }
        ]
      },
      "PersonQuarantined": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Person"
          },
          {
            "type": "object",
            "properties": {
              "sessions_cut": {
                "type": "integer",
                "description": "Device and browser sessions that were cut."
              }
            }
          }
        ]
      },
      "PersonAccess": {
        "type": "object",
        "properties": {
          "person_id": {
            "type": "string"
          },
          "suspended": {
            "type": "boolean"
          },
          "groups": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "devices": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "device_id": {
                  "type": "string"
                },
                "device_name": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "trust": {
                  "type": "string",
                  "enum": [
                    "trusted",
                    "untrusted"
                  ],
                  "description": "Device trust right now."
                },
                "quarantined": {
                  "type": "boolean"
                },
                "posture_freshness": {
                  "type": "string",
                  "enum": [
                    "fresh",
                    "stale",
                    "none"
                  ],
                  "description": "Whether the device's last posture report is recent."
                },
                "granted": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "kind": {
                        "type": "string",
                        "enum": [
                          "connection",
                          "private_network"
                        ]
                      },
                      "id": {
                        "type": "string"
                      },
                      "name": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "granted_by": {
                        "type": "object",
                        "properties": {
                          "rule_id": {
                            "type": "string"
                          },
                          "rule_name": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  },
                  "description": "What this device can reach now, and the access rule that grants it."
                },
                "blocked": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "kind": {
                        "type": "string",
                        "enum": [
                          "connection",
                          "private_network"
                        ]
                      },
                      "id": {
                        "type": "string"
                      },
                      "name": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "rule": {
                        "type": "object",
                        "properties": {
                          "rule_id": {
                            "type": "string"
                          },
                          "rule_name": {
                            "type": "string"
                          }
                        }
                      },
                      "missing_posture": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "description": "Posture profiles the device does not meet."
                      },
                      "needs_trusted_device": {
                        "type": "boolean"
                      },
                      "person_suspended": {
                        "type": "boolean"
                      }
                    }
                  },
                  "description": "What a rule would grant through the person's groups but a device condition blocks."
                }
              }
            }
          },
          "portal": {
            "type": "object",
            "properties": {
              "tiles": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "granted_by": {
                      "type": "object",
                      "properties": {
                        "rule_id": {
                          "type": "string"
                        },
                        "rule_name": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "description": "Browser portal apps the person sees."
              },
              "hidden": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "reason": {
                      "type": "string",
                      "description": "Why the app is not shown, in plain English."
                    },
                    "locked": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "description": "Set when the app is shown locked (allowed, but not from a browser): what is needed."
                    }
                  }
                }
              }
            }
          },
          "evaluated_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "person_id",
          "devices",
          "portal",
          "evaluated_at"
        ]
      },
      "PersonInvitation": {
        "type": "object",
        "properties": {
          "person_id": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "state": {
            "type": "string",
            "enum": [
              "invited"
            ]
          },
          "invited_at": {
            "type": "string",
            "format": "date-time"
          },
          "invite_count": {
            "type": "integer"
          },
          "sign_in": {
            "type": "object",
            "properties": {
              "method": {
                "type": "string"
              },
              "second_factor": {
                "type": "string"
              }
            }
          }
        },
        "required": [
          "person_id",
          "state"
        ]
      },
      "PersonUnlock": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Person id."
          },
          "unlocked": {
            "type": "boolean"
          },
          "was_locked": {
            "type": "boolean",
            "description": "False when the sign-in was not locked to begin with."
          }
        },
        "required": [
          "id",
          "unlocked"
        ]
      },
      "PortalSignout": {
        "type": "object",
        "properties": {
          "person_id": {
            "type": "string"
          },
          "portal_sessions_ended": {
            "type": "integer",
            "description": "Browser portal sign-ins that were ended."
          },
          "browser_sessions_cut": {
            "type": "integer",
            "description": "Open browser app sessions that were cut."
          },
          "overlay": {
            "type": "string",
            "enum": [
              "ok",
              "unavailable"
            ],
            "description": "`unavailable` = open browser sessions could not be checked right now (portal sign-ins were still ended)."
          }
        },
        "required": [
          "person_id",
          "portal_sessions_ended",
          "browser_sessions_cut"
        ]
      },
      "BulkInviteResult": {
        "type": "object",
        "properties": {
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "email": {
                  "type": "string"
                },
                "person_id": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "outcome": {
                  "type": "string",
                  "enum": [
                    "invited",
                    "invalid-email",
                    "duplicate",
                    "seat-quota-reached",
                    "pending-approval",
                    "suspended",
                    "already-active",
                    "recently-invited",
                    "federated-sign-in",
                    "failed"
                  ]
                }
              },
              "required": [
                "email",
                "outcome"
              ]
            },
            "description": "One row per input row, in order."
          },
          "counts": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            },
            "description": "Number of rows per outcome."
          }
        },
        "required": [
          "results",
          "counts"
        ]
      },
      "Group": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Group id."
          },
          "display_name": {
            "type": "string",
            "description": "Name, 1-80 characters, unique in the workspace (case-insensitive)."
          },
          "source": {
            "type": "string",
            "enum": [
              "local",
              "ad",
              "scim",
              "directory"
            ],
            "description": "`local` = created in Cloudraw (editable here); `ad` = imported from Active Directory; `scim` / `directory` = managed by your directory."
          },
          "dn": {
            "type": "string",
            "description": "Only for `ad` groups: the distinguished name in Active Directory."
          },
          "member_count": {
            "type": "integer"
          },
          "members": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "email": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              }
            }
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "display_name",
          "source",
          "member_count",
          "members"
        ]
      },
      "GroupListItem": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Group"
          },
          {
            "type": "object",
            "properties": {
              "used_by_rules": {
                "type": "integer",
                "description": "Access and trust rules that match on this group."
              }
            }
          }
        ]
      },
      "GroupDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Group"
          },
          {
            "type": "object",
            "properties": {
              "used_by_rules": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "kind": {
                      "type": "string",
                      "enum": [
                        "trust"
                      ],
                      "description": "Present (`trust`) for trust rules; absent for access rules."
                    }
                  }
                },
                "description": "Rules that match on this group."
              }
            }
          }
        ]
      },
      "GroupList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GroupListItem"
            }
          },
          "directory_source": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "ad",
              "scim",
              null
            ],
            "description": "The connected directory, if any."
          }
        },
        "required": [
          "items"
        ]
      },
      "DeviceTrustUnmet": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "description": "`posture`, `group`, `person`, `device`, `network`, `reauth` …"
          },
          "field": {
            "type": [
              "string",
              "null"
            ],
            "description": "The condition field, e.g. `disk_encrypted`, `country`, `last_auth_at`."
          },
          "op": {
            "type": [
              "string",
              "null"
            ]
          },
          "value": {
            "description": "What the rule wants."
          },
          "got": {
            "description": "What the device reported (null = not reported)."
          },
          "text": {
            "type": "string",
            "description": "Plain-English explanation, safe to show to the device user."
          }
        },
        "required": [
          "kind",
          "text"
        ]
      },
      "DeviceTrust": {
        "type": "object",
        "properties": {
          "device_id": {
            "type": "string"
          },
          "state": {
            "type": "string",
            "enum": [
              "trusted",
              "untrusted"
            ],
            "description": "Trust decision right now."
          },
          "reason": {
            "type": "string",
            "description": "Plain-English reason for the decision."
          },
          "unmet": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DeviceTrustUnmet"
            },
            "description": "What keeps the device from being trusted (empty when trusted or when no rule applies)."
          },
          "evaluated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When this decision was computed (now)."
          },
          "source": {
            "type": "string",
            "enum": [
              "default",
              "manual",
              "rule",
              "policy"
            ],
            "description": "`default` = the workspace has no trust rules yet; `manual` = set by an admin; `rule` = your trust rules; `policy` = a workspace policy (sign-in required, person suspended)."
          },
          "manual": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "trusted",
              "untrusted",
              null
            ],
            "description": "Manual override set by an admin; null = automatic (your trust rules decide)."
          }
        },
        "required": [
          "device_id",
          "state",
          "source"
        ]
      },
      "DevicePosture": {
        "type": "object",
        "properties": {
          "compliant": {
            "type": "boolean",
            "description": "Core health checks pass (disk encryption, antivirus on, firewall on, system up to date, screen lock not off)."
          },
          "checks": {
            "type": "object",
            "additionalProperties": {
              "type": "boolean"
            },
            "description": "Derived checks, e.g. `disk_encrypted`, `antivirus_present`, `antivirus_on`, `edr_present`, `firewall_on`, `screen_lock`, `os_up_to_date`, `domain_joined`, `entra_joined`, `mdm_enrolled`, `workgroup`, `managed`. A check the device did not report is absent."
          },
          "evaluated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When Cloudraw received the report."
          },
          "source": {
            "type": "string",
            "description": "`device` (Cloudraw Connect health report) or `api`."
          },
          "client_version": {
            "type": [
              "string",
              "null"
            ],
            "description": "Cloudraw Connect app version that sent the report."
          },
          "os": {
            "type": [
              "object",
              "null"
            ],
            "description": "Operating system as reported (family, version, build, edition, server, last_update_installed_at, pending_reboot …)."
          },
          "disk_encryption": {
            "type": [
              "object",
              "null"
            ],
            "description": "os_volume (`on` | `off` | `suspended` | `unknown`), method, os_volume_percent, fixed_volumes_all_on."
          },
          "antivirus": {
            "type": [
              "array",
              "null"
            ],
            "description": "Antivirus products: name, enabled, up_to_date."
          },
          "edr": {
            "type": [
              "array",
              "null"
            ],
            "description": "Endpoint sensors: name, running."
          },
          "firewall": {
            "type": [
              "object",
              "null"
            ],
            "description": "domain / private / public profile state (booleans or null)."
          },
          "screen_lock": {
            "type": [
              "object",
              "null"
            ],
            "description": "enabled, timeout_s."
          },
          "joins": {
            "type": [
              "object",
              "null"
            ],
            "description": "domain_joined, entra_joined, mdm_enrolled (null = not reported)."
          },
          "freshness": {
            "type": "string",
            "enum": [
              "fresh",
              "held",
              "stale"
            ],
            "description": "`stale` = the device has not reported recently and its checks no longer count; `held` = last report kept during a wide reporting outage."
          },
          "age_s": {
            "type": "integer",
            "description": "Seconds since the report."
          }
        },
        "required": [
          "compliant",
          "checks",
          "evaluated_at"
        ],
        "description": "Last health report from the device. Self-asserted by the device."
      },
      "DeviceHealth": {
        "type": "object",
        "properties": {
          "state": {
            "type": "string",
            "enum": [
              "not_reported",
              "ok",
              "requirements_not_met",
              "stale"
            ]
          },
          "summary": {
            "type": "string",
            "description": "One line for people, e.g. \"Meets all 3 required checks\"."
          },
          "stale": {
            "type": "boolean"
          },
          "requirements": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "field": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "expected": {
                  "type": "boolean"
                },
                "met": {
                  "type": "boolean"
                },
                "text": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              }
            },
            "description": "Checks that YOUR trust and access rules require of this device."
          },
          "recommendations": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "field": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "text": {
                  "type": "string"
                }
              }
            },
            "description": "Good-practice checks that fail but no rule requires."
          },
          "facts": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "field": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "value": {
                  "type": "boolean"
                }
              }
            },
            "description": "Plain facts (domain joined, MDM enrolled …)."
          },
          "reported_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "state",
          "summary"
        ]
      },
      "Device": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Device id."
          },
          "name": {
            "type": "string",
            "description": "Device name in the workspace (lowercase, `-` separated)."
          },
          "short_id": {
            "type": "string",
            "description": "Last 6 characters of the id, for display."
          },
          "identity_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Id of the device's network identity."
          },
          "os": {
            "type": [
              "string",
              "null"
            ],
            "description": "Operating system label, e.g. \"Windows 11 Pro\"."
          },
          "os_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "os_version": {
            "type": [
              "string",
              "null"
            ]
          },
          "hostname": {
            "type": [
              "string",
              "null"
            ],
            "description": "Computer name reported by the device (kept while offline)."
          },
          "client_app": {
            "type": [
              "string",
              "null"
            ],
            "description": "Client app name, normally \"Cloudraw Connect\"."
          },
          "public_ip_masked": {
            "type": [
              "string",
              "null"
            ],
            "description": "Last public IP seen from the device, masked. The full address is only shown in the console (audited)."
          },
          "public_ip_version": {
            "type": [
              "integer",
              "null"
            ],
            "enum": [
              4,
              6,
              null
            ]
          },
          "public_ip_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "public_ip_source": {
            "type": [
              "string",
              "null"
            ]
          },
          "hostname_shared": {
            "type": "boolean",
            "description": "Another enrolled device or connector reports the same computer name (e.g. cloned machines)."
          },
          "hostname_shared_with": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "kind": {
                  "type": "string",
                  "enum": [
                    "device",
                    "connector"
                  ]
                },
                "id": {
                  "type": "string"
                },
                "short_id": {
                  "type": "string"
                },
                "name": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              }
            }
          },
          "person_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Person the device belongs to."
          },
          "person_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_by_integrator": {
            "type": [
              "object",
              "null"
            ],
            "description": "Set when an integrator (partner) you approved created this record from its own account; null otherwise.",
            "properties": {
              "kind": {
                "type": "string",
                "description": "Always `partner`."
              },
              "partner_id": {
                "type": "string"
              },
              "partner_name": {
                "type": "string"
              },
              "member": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Which of the integrator's staff."
              },
              "member_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "at": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "online": {
            "type": "boolean",
            "description": "Connected right now."
          },
          "status_known": {
            "type": "boolean",
            "description": "false = Cloudraw could not read the live status just now; `online` and `last_seen` are the last known values."
          },
          "last_seen": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "access": {
            "type": "string",
            "enum": [
              "allowed",
              "blocked"
            ],
            "description": "Can this device reach anything right now?"
          },
          "blocked_by": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "quarantine",
              "admin",
              "sign_in_required",
              "trust_rules",
              "person_deleted",
              "person_suspended",
              null
            ],
            "description": "Why it is blocked; null when allowed."
          },
          "quarantined": {
            "type": "boolean"
          },
          "quarantined_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "quarantine_reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "trust": {
            "type": "object",
            "properties": {
              "state": {
                "type": "string",
                "enum": [
                  "trusted",
                  "untrusted"
                ],
                "description": "Trust decision right now."
              },
              "reason": {
                "type": "string",
                "description": "Plain-English reason for the decision."
              },
              "unmet": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/DeviceTrustUnmet"
                },
                "description": "What keeps the device from being trusted (empty when trusted or when no rule applies)."
              },
              "evaluated_at": {
                "type": "string",
                "format": "date-time",
                "description": "When this decision was computed (now)."
              },
              "source": {
                "type": "string",
                "enum": [
                  "default",
                  "manual",
                  "rule",
                  "policy"
                ],
                "description": "`default` = the workspace has no trust rules yet; `manual` = set by an admin; `rule` = your trust rules; `policy` = a workspace policy (sign-in required, person suspended)."
              },
              "manual": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "trusted",
                  "untrusted",
                  null
                ]
              }
            },
            "required": [
              "state",
              "source"
            ]
          },
          "health": {
            "$ref": "#/components/schemas/DeviceHealth"
          },
          "posture": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/DevicePosture"
              },
              {
                "type": "null"
              }
            ]
          },
          "bitlocker": {
            "type": [
              "object",
              "null"
            ],
            "description": "BitLocker readiness reported by the device (status `PASS` | `WARN` | `ROADBLOCK`, findings with fix text, stale flag). Advice only, never an access decision. Null until reported."
          },
          "web_filter": {
            "type": [
              "object",
              "null"
            ],
            "description": "Web filter state reported by Cloudraw Connect (0.4.12+): `state` `on` | `off` | `paused_multi_workspace` | `unknown`, `enabled`, `multi_workspace`, `reason`, `message` (plain text when paused), counters `blocked` `monitored` `warned` `requests`, `received_at`. `paused_multi_workspace` = the device is in more than one Cloudraw workspace, so web filtering is paused on it. Null until reported."
          },
          "app_firewall": {
            "type": "object",
            "properties": {
              "capable": {
                "type": "boolean",
                "description": "The device runs a Cloudraw Connect version that enforces allowed applications."
              },
              "client_version": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "connect": {
            "type": "object",
            "properties": {
              "version": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Cloudraw Connect app version."
              },
              "latest": {
                "type": "string",
                "description": "Latest published version."
              },
              "update_available": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "reported": {
                "type": "boolean"
              }
            }
          },
          "connect_version": {
            "type": [
              "string",
              "null"
            ],
            "description": "Cloudraw Connect app version from its own health report (same as connect.version); null = never reported. Not inventory.client_version (that is the tunnel)."
          },
          "connect_version_reported_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When Cloudraw received the health report that carried connect_version (null with it)."
          },
          "inventory": {
            "type": "object",
            "properties": {
              "client_version": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "hostname": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "os": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "os_version": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "remote_assist": {
            "type": "object",
            "properties": {
              "available": {
                "type": "boolean"
              },
              "eligible": {
                "type": "boolean"
              },
              "modes": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "reason": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "description": "Remote assistance availability for this device."
          },
          "state": {
            "type": "string",
            "description": "Always `approved`."
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "enrolled_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the device first joined."
          },
          "enrollment_used": {
            "type": "boolean",
            "description": "The device ever came up (enrolled, seen online or reported)."
          },
          "created_via": {
            "type": "string",
            "enum": [
              "admin-enrolment",
              "sign-in",
              "fleet-token"
            ],
            "description": "How the device was added."
          },
          "enrolled_by": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "kind": {
                "type": "string",
                "enum": [
                  "admin",
                  "fleet_token",
                  "person"
                ]
              },
              "id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "label": {
                "type": "string"
              }
            }
          },
          "delivery": {
            "type": [
              "string",
              "null"
            ],
            "description": "Enrollment method: `sso` (sign-in), `provision` (fleet token), or what the admin chose at creation (`token`, `code`, `qr`, `email`)."
          },
          "last_auth_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Last time the device's person signed in on it (sign-in enrolled devices)."
          },
          "last_resource_sync_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "sync_requested": {
            "type": "boolean"
          }
        },
        "required": [
          "id",
          "name",
          "online",
          "access",
          "trust"
        ]
      },
      "DeviceList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Device"
            }
          },
          "next_page": {
            "type": "null",
            "description": "Always null: the list is bounded by the device quota and returned whole."
          },
          "connect_latest": {
            "type": "string",
            "description": "Latest published Cloudraw Connect version."
          }
        },
        "required": [
          "items"
        ]
      },
      "DeviceOwnerChange": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "device_name": {
            "type": "string"
          },
          "person_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "person_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "previous_person_id": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "person_id"
        ]
      },
      "DeviceRemoval": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Task id."
          },
          "tenant_id": {
            "type": "string"
          },
          "state": {
            "type": "string",
            "description": "`done`."
          },
          "result_uri": {
            "type": "null"
          },
          "error": {
            "type": "null"
          },
          "removed": {
            "type": "object",
            "properties": {
              "identity": {
                "type": "boolean",
                "description": "The device's network identity was deleted."
              },
              "circuits_closed": {
                "type": "integer",
                "description": "Live connections cut."
              },
              "rules_updated": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Access rules that named this device and were updated."
              },
              "jit_grants_revoked": {
                "type": "integer"
              },
              "enrolment_codes_revoked": {
                "type": "integer"
              }
            }
          }
        },
        "required": [
          "id",
          "state",
          "removed"
        ]
      },
      "DeviceAccessHistoryEntry": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "device",
              "browser",
              "other"
            ]
          },
          "device_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "device_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "person_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "user": {
            "type": [
              "string",
              "null"
            ]
          },
          "app": {
            "type": [
              "string",
              "null"
            ],
            "description": "App or private network name."
          },
          "connection_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "private_network_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "target": {
            "type": [
              "object",
              "null"
            ],
            "description": "{type, host, port} for an app; {type: \"private_network\", cidrs, translated_cidr} for a private network."
          },
          "via": {
            "type": "string",
            "enum": [
              "cloudraw connect",
              "browser",
              "vendor access"
            ]
          },
          "dst": {
            "type": [
              "object",
              "null"
            ],
            "description": "Exact destination reported by the connector: {proto, ip, port}."
          },
          "bytes_in": {
            "type": [
              "integer",
              "null"
            ]
          },
          "bytes_out": {
            "type": [
              "integer",
              "null"
            ]
          },
          "end_reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "started_at": {
            "type": "string",
            "format": "date-time"
          },
          "ended_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "duration_s": {
            "type": [
              "integer",
              "null"
            ]
          },
          "live": {
            "type": "boolean",
            "description": "The session is still open."
          },
          "probe": {
            "type": "boolean",
            "description": "Only with `include_probes=true`: an automatic Cloudraw Connect reachability check."
          },
          "probe_anomaly": {
            "type": "boolean",
            "description": "More than one check-like connection per 2-minute beat for this device + app."
          }
        },
        "required": [
          "id",
          "started_at",
          "live"
        ]
      },
      "DeviceAccessHistory": {
        "type": "object",
        "properties": {
          "device_id": {
            "type": "string"
          },
          "days": {
            "type": "integer",
            "description": "Window used."
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DeviceAccessHistoryEntry"
            },
            "description": "Newest first."
          },
          "by_app": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "app": {
                  "type": "string"
                },
                "sessions": {
                  "type": "integer"
                },
                "total_s": {
                  "type": "integer"
                }
              }
            },
            "description": "Totals per app over the whole window (not only the returned page)."
          },
          "probes_excluded": {
            "type": "integer",
            "description": "Cloudraw Connect reachability checks left out; 0 with `include_probes=true`."
          },
          "probes_included": {
            "type": "integer",
            "description": "Only with `include_probes=true`: how many listed entries are reachability checks."
          },
          "retention_days": {
            "type": "integer"
          },
          "note": {
            "type": "string"
          }
        },
        "required": [
          "device_id",
          "items"
        ]
      },
      "DeviceQuarantineResult": {
        "type": "object",
        "properties": {
          "dry_run": {
            "type": "boolean"
          },
          "device_id": {
            "type": "string"
          },
          "device": {
            "type": "string",
            "description": "Device name."
          },
          "resources": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "kind": {
                  "type": "string",
                  "enum": [
                    "connection",
                    "smb",
                    "private_network"
                  ]
                },
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                }
              }
            },
            "description": "What the device can reach now (and loses)."
          },
          "live_sessions": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "app": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "started_at": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            },
            "description": "Open sessions of the device; null when they could not be read."
          },
          "overlay": {
            "type": "string",
            "enum": [
              "ok",
              "unavailable"
            ],
            "description": "`unavailable` = live sessions could not be read right now."
          },
          "already_quarantined": {
            "type": "boolean"
          },
          "sessions_cut": {
            "type": "integer",
            "description": "Only when `dry_run` is false."
          },
          "sessions_failed": {
            "type": "integer",
            "description": "Sessions still open after the cut (only when `dry_run` is false)."
          },
          "trust": {
            "type": "object",
            "description": "The device trust after the change (only when `dry_run` is false)."
          }
        },
        "required": [
          "dry_run",
          "device_id"
        ]
      },
      "FleetCompliance": {
        "type": "object",
        "properties": {
          "total_devices": {
            "type": "integer"
          },
          "evaluated": {
            "type": "integer",
            "description": "Devices that have sent a health report."
          },
          "compliant": {
            "type": "integer",
            "description": "Devices that meet every check your rules require (fresh report)."
          },
          "stale": {
            "type": "integer",
            "description": "Devices whose last report is too old."
          },
          "percent": {
            "type": [
              "integer",
              "null"
            ],
            "description": "compliant / evaluated, rounded; null when no device reported."
          },
          "basis": {
            "type": "string",
            "description": "Always `workspace-rules`: the checks your trust and access rules require."
          }
        },
        "required": [
          "total_devices",
          "evaluated",
          "compliant",
          "percent"
        ]
      },
      "EnrollmentCreated": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Enrollment id; also the id of the device once it joins."
          },
          "kind": {
            "type": "string",
            "description": "`device`."
          },
          "state": {
            "type": "string",
            "description": "`issued`."
          },
          "jwt": {
            "type": "string",
            "description": "One-time enrollment token (shown once). Valid until `expires_at`."
          },
          "claim_code": {
            "type": "string",
            "description": "Short code the user types in Cloudraw Connect, `CRW-XXXXX-XXXXX` (shown once). Valid 1 hour."
          },
          "claim_url": {
            "type": "string",
            "description": "Link that opens Cloudraw Connect with the code (shown once)."
          },
          "claim_expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "qr_png_base64": {
            "type": "null"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the enrollment token expires (7 days)."
          }
        },
        "required": [
          "id",
          "jwt",
          "claim_code",
          "claim_url",
          "expires_at"
        ]
      },
      "Enrollment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "description": "`device`."
          },
          "state": {
            "type": "string",
            "description": "`issued` (not used yet)."
          },
          "device_name": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "created_by_integrator": {
            "type": [
              "object",
              "null"
            ],
            "description": "Set when an integrator (partner) you approved created this record from its own account; null otherwise.",
            "properties": {
              "kind": {
                "type": "string",
                "description": "Always `partner`."
              },
              "partner_id": {
                "type": "string"
              },
              "partner_name": {
                "type": "string"
              },
              "member": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Which of the integrator's staff."
              },
              "member_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "at": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "claim_expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Expiry of the live short code; null when no code is live (a new one can be issued in the console)."
          }
        },
        "required": [
          "id",
          "device_name",
          "expires_at"
        ]
      },
      "EnrollmentList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Enrollment"
            },
            "description": "Newest first."
          },
          "next_cursor": {
            "type": "null",
            "description": "Always null: the list is bounded by the device quota."
          }
        },
        "required": [
          "items"
        ]
      },
      "EnrollmentDetail": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "device_name": {
            "type": "string"
          },
          "claim_code": {
            "type": "null",
            "description": "Never returned here."
          },
          "claim_url": {
            "type": "null"
          },
          "claim_expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "reveal_with": {
            "type": "object",
            "properties": {
              "method": {
                "type": "string"
              },
              "path": {
                "type": "string"
              }
            },
            "description": "The call that issues a fresh short code (and invalidates the previous one)."
          }
        },
        "required": [
          "id",
          "expires_at"
        ]
      },
      "ConnectorUpdateStatus": {
        "type": "object",
        "properties": {
          "mode": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "immediate",
              "auto_window",
              "manual",
              "paused",
              null
            ],
            "description": "The mode this connector follows now: its own override, else the workspace connector default; `paused` wins over both."
          },
          "mode_source": {
            "type": "string",
            "enum": [
              "connector",
              "workspace",
              "paused"
            ],
            "description": "`connector` = set on this connector; `workspace` = inherited from the update policy; `paused` = updates paused on purpose."
          },
          "mode_override": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "immediate",
              "auto_window",
              "manual",
              null
            ],
            "description": "This connector's own mode; null = follows the workspace."
          },
          "mode_override_by": {
            "type": [
              "string",
              "null"
            ],
            "description": "Who set the override."
          },
          "mode_override_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the override was set."
          },
          "rollout": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "state": {
                    "type": "string",
                    "enum": [
                      "staged",
                      "held",
                      "open"
                    ],
                    "description": "`staged` = waiting for the staged rollout (the canary group takes the version first); `held` = the version is on hold after a failed update somewhere (Cloudraw releases it once fixed); `open` = released, the connector installs it according to its update mode."
                  },
                  "version": {
                    "type": "string",
                    "description": "The version being rolled out (the current feed version)."
                  },
                  "reason": {
                    "type": "string",
                    "enum": [
                      "waiting_for_canaries",
                      "soaking",
                      "failed_update",
                      "canaries_ok",
                      "operator_opened",
                      "canary"
                    ],
                    "description": "Why: `waiting_for_canaries` (no estimate yet), `soaking` (enough canaries succeeded; opens at `expected_at`), `failed_update`, `canaries_ok`, `operator_opened` (released by Cloudraw by hand), `canary` (this connector is in the canary group)."
                  },
                  "detail": {
                    "type": "string",
                    "description": "The same in plain words, ready to show."
                  },
                  "since": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date-time",
                    "description": "When this state began (version first seen / frozen / opened)."
                  },
                  "expected_at": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date-time",
                    "description": "When a `staged` version is expected to open; null when not known yet (and for `held` / `open`)."
                  },
                  "canary": {
                    "type": "boolean",
                    "description": "True when this connector is in the canary group."
                  }
                },
                "required": [
                  "state",
                  "version",
                  "reason",
                  "expected_at"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Staged rollout of the newest connector version as it applies to this connector. null = nothing to show (the connector already runs it, or staged rollout is off)."
          },
          "current_version": {
            "type": [
              "string",
              "null"
            ],
            "description": "Version the connector runs, Cloudraw build included (e.g. `1.18.7-b11c`); null until it reported one."
          },
          "build_known": {
            "type": "boolean",
            "description": "True when `current_version` carries the Cloudraw build suffix (`-b<n>`)."
          },
          "available_version": {
            "type": [
              "string",
              "null"
            ],
            "description": "Newer version the connector can update to; null when it is up to date."
          },
          "previous_version": {
            "type": [
              "string",
              "null"
            ],
            "description": "Version before the last update."
          },
          "requested_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When an \"Update now\" was requested and not yet applied."
          },
          "applied_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the last update was applied."
          },
          "last_check_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Last time the connector's updater checked in (every 15 minutes when healthy)."
          },
          "last": {
            "type": "object",
            "properties": {
              "ok": {
                "type": "boolean"
              },
              "from": {
                "type": "string"
              },
              "to": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "at": {
                "type": "string",
                "format": "date-time"
              }
            },
            "description": "Result of the last update attempt (empty object when there was none)."
          },
          "updater": {
            "type": "boolean",
            "description": "True when an update token was issued for this connector (an updater can be installed)."
          },
          "token_rotated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the updater last replaced the token from its install command by its own."
          },
          "paused": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "at": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "by": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "reason": {
                    "type": "string"
                  }
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "Set while automatic updates are paused on purpose."
          },
          "last_paused": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "at": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "by": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "reason": {
                    "type": "string"
                  },
                  "resumed_at": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "resumed_by": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "The previous pause, after a resume."
          },
          "updater_state": {
            "type": "string",
            "enum": [
              "ok",
              "stale",
              "never_checked",
              "token_rejected",
              "paused",
              "none"
            ],
            "description": "`ok` = checked in within 2 h; `stale` = no check for over 2 h; `never_checked` = no check ever arrived (installed before automatic updates: use `enable-updates`); `token_rejected` = an updater calls in with an outdated token (run the newest `enable-updates` command once); `paused` = paused on purpose; `none` = no updater."
          },
          "last_reject_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Last time an updater called in with an outdated token."
          }
        },
        "required": [
          "updater_state"
        ],
        "description": "Automatic-update state of one connector."
      },
      "ConnectorTrust": {
        "type": "object",
        "properties": {
          "state": {
            "type": "string",
            "enum": [
              "trusted",
              "untrusted",
              "pending"
            ],
            "description": "A connector hosts apps and private networks only while `trusted`; otherwise it is kept offline."
          },
          "reason": {
            "type": "string",
            "description": "Why, in plain words."
          },
          "source": {
            "type": "string",
            "enum": [
              "manual",
              "policy",
              "default",
              "removal"
            ],
            "description": "What decided: an admin's manual approve / block, the connector trust policy, the default, or a pending removal."
          },
          "evaluated_at": {
            "type": "string",
            "format": "date-time"
          },
          "manual": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "trusted",
              "untrusted",
              null
            ],
            "description": "Manual decision of an admin, if any (set in the console)."
          },
          "approved": {
            "type": "boolean",
            "description": "Approved by an admin (matters when the trust policy requires approval)."
          }
        },
        "required": [
          "state",
          "source"
        ]
      },
      "Connector": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Connector id."
          },
          "name": {
            "type": "string",
            "description": "Name (lower-case, dashes; derived from the name given at creation, at most 40 characters)."
          },
          "platform": {
            "type": "string",
            "enum": [
              "windows",
              "linux",
              "deb",
              "rpm",
              "docker"
            ],
            "description": "Install platform chosen at creation."
          },
          "online": {
            "type": "boolean",
            "description": "Connected right now."
          },
          "enrolled": {
            "type": "boolean",
            "description": "Installed: the connector used its enrolment token at least once (stays true while offline)."
          },
          "hostname": {
            "type": [
              "string",
              "null"
            ],
            "description": "Host name the connector reports (last known)."
          },
          "os": {
            "type": [
              "string",
              "null"
            ]
          },
          "os_version": {
            "type": [
              "string",
              "null"
            ]
          },
          "last_seen": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Last time it was seen online."
          },
          "sw_version": {
            "type": [
              "string",
              "null"
            ],
            "description": "Version it runs, Cloudraw build included."
          },
          "tunnel_version": {
            "type": [
              "string",
              "null"
            ],
            "description": "Bare tunnel version without the Cloudraw build."
          },
          "pending_removal": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "at": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "by": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "purge_at": {
                    "type": "string",
                    "format": "date-time"
                  }
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "Set after a remove in the console: the connector no longer hosts and is deleted for good at `purge_at` unless restored."
          },
          "public_ip": {
            "type": [
              "string",
              "null"
            ],
            "description": "Always null for API tokens (only owners and security admins in the console see it). Use `public_ip_masked`."
          },
          "public_ip_masked": {
            "type": [
              "string",
              "null"
            ],
            "description": "Public egress IP with the last part masked (`203.0.113.x`)."
          },
          "public_ip_version": {
            "type": [
              "integer",
              "null"
            ],
            "enum": [
              4,
              6,
              null
            ]
          },
          "public_ip_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the public IP was last seen."
          },
          "public_ip_source": {
            "type": [
              "string",
              "null"
            ],
            "description": "How it was learned (`updater-check`)."
          },
          "update": {
            "$ref": "#/components/schemas/ConnectorUpdateStatus"
          },
          "remote_app_helper": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "RemoteApp helper switch (on unless switched off)."
              },
              "last_seen": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "programs_listed_at": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              }
            },
            "required": [
              "enabled"
            ],
            "description": "RemoteApp helper (Windows connector installed on the RDP server itself)."
          },
          "guides": {
            "type": "object",
            "properties": {
              "install": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "section": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "title": {
                    "type": "string"
                  },
                  "url": {
                    "type": "string",
                    "description": "Web page of the guide."
                  },
                  "pdf_url": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "PDF version, if any."
                  }
                },
                "required": [
                  "id",
                  "url"
                ],
                "description": "A setup-guide link."
              },
              "updates": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "section": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "title": {
                    "type": "string"
                  },
                  "url": {
                    "type": "string",
                    "description": "Web page of the guide."
                  },
                  "pdf_url": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "PDF version, if any."
                  }
                },
                "required": [
                  "id",
                  "url"
                ],
                "description": "A setup-guide link."
              },
              "high_availability": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "section": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "title": {
                    "type": "string"
                  },
                  "url": {
                    "type": "string",
                    "description": "Web page of the guide."
                  },
                  "pdf_url": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "PDF version, if any."
                  }
                },
                "required": [
                  "id",
                  "url"
                ],
                "description": "A setup-guide link."
              },
              "remoteapp_helper": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "section": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "title": {
                    "type": "string"
                  },
                  "url": {
                    "type": "string",
                    "description": "Web page of the guide."
                  },
                  "pdf_url": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "PDF version, if any."
                  }
                },
                "required": [
                  "id",
                  "url"
                ],
                "description": "A setup-guide link."
              }
            },
            "description": "Setup-guide links for this connector."
          },
          "status": {
            "type": "object",
            "properties": {
              "phase": {
                "type": "string",
                "enum": [
                  "pending",
                  "ready"
                ],
                "description": "`pending` until the connector first comes online."
              },
              "observed_at": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "message": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "version": {
            "type": "integer",
            "description": "Increases on every change of the record."
          },
          "created_by_integrator": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string"
                  },
                  "partner_id": {
                    "type": "string"
                  },
                  "partner_name": {
                    "type": "string"
                  },
                  "member": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "member_id": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "at": {
                    "type": "string",
                    "format": "date-time"
                  }
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "Set when an integrator created the connector."
          },
          "claim_burned_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "bitlocker": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "PASS",
                      "WARN",
                      "ROADBLOCK"
                    ]
                  },
                  "reported_status": {
                    "type": "string"
                  },
                  "findings": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "severity": {
                          "type": "string",
                          "enum": [
                            "ROADBLOCK",
                            "WARN",
                            "INFO"
                          ]
                        },
                        "fix_text": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    }
                  },
                  "roadblocks": {
                    "type": "integer"
                  },
                  "warnings": {
                    "type": "integer"
                  },
                  "truncated": {
                    "type": "boolean"
                  },
                  "dropped": {
                    "type": "integer"
                  },
                  "checked_at": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date-time"
                  },
                  "script_version": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "received_at": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "source": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "stale": {
                    "type": "boolean",
                    "description": "Older than 7 days."
                  }
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "BitLocker readiness of the connector computer from its last diagnostics report; null when none was received."
          },
          "short_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Last 6 characters of the id, for display. (List and PATCH answers.)"
          },
          "identity_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Id of the connector's enrolled network identity, its key. Two records with the same host name but different identity ids are different machines. (List and PATCH answers.)"
          },
          "hostname_shared": {
            "type": "boolean",
            "description": "True when another enrolled connector or device of the workspace reports the same host name (often a cloned VM). (List and PATCH answers.)"
          },
          "hostname_shared_with": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "kind": {
                  "type": "string",
                  "enum": [
                    "connector",
                    "device"
                  ]
                },
                "id": {
                  "type": "string"
                },
                "short_id": {
                  "type": "string"
                },
                "name": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              }
            },
            "description": "The others with that host name (up to 10)."
          },
          "trust": {
            "$ref": "#/components/schemas/ConnectorTrust"
          },
          "hosting_summary": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "expected": {
                    "type": "integer"
                  },
                  "hosted": {
                    "type": "integer"
                  },
                  "missing": {
                    "type": "integer"
                  },
                  "partial": {
                    "type": "integer"
                  },
                  "checked_at": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date-time"
                  }
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "List answers only: how many apps / private networks the connector should host vs really hosts, from a recent check; null when none was made recently (call `…/hosting`)."
          }
        },
        "required": [
          "id",
          "name",
          "platform",
          "online",
          "enrolled",
          "status",
          "version"
        ]
      },
      "ConnectorList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Connector"
            }
          },
          "next_page": {
            "type": "null",
            "description": "Always null: the list is not paginated (bounded by your plan's connector limit)."
          }
        },
        "required": [
          "items"
        ]
      },
      "WindowsConnectorInstaller": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "description": "Download URL of the signed Windows setup program."
          },
          "file_name": {
            "type": "string"
          },
          "sha256": {
            "type": "string",
            "description": "SHA-256 of the file."
          },
          "signer": {
            "type": "string",
            "description": "Code-signing publisher."
          },
          "version": {
            "type": "string"
          },
          "silent_command": {
            "type": [
              "string",
              "null"
            ],
            "description": "Silent install with the claim code (`<file> /S /CODE=<claim_code>`); null when the answer carries no code."
          },
          "silent_command_file": {
            "type": [
              "string",
              "null"
            ],
            "description": "Silent install reading the code from a file, when the build supports it."
          }
        },
        "required": [
          "url",
          "file_name",
          "sha256"
        ]
      },
      "ConnectorInstall": {
        "type": "object",
        "properties": {
          "connector": {
            "$ref": "#/components/schemas/Connector"
          },
          "install_command": {
            "type": [
              "string",
              "null"
            ],
            "description": "The one command to run on the connector host (see the operation description). Shown once."
          },
          "claim_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Short one-time install link the command fetches. Valid 24 hours, dies once the connector is installed or a newer install code is made."
          },
          "claim_expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When `claim_url` / `claim_code` expire (24 h)."
          },
          "claim_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "Windows only: the bare 16-character code the signed setup program takes (`/CODE=`). Single use."
          },
          "installer": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/WindowsConnectorInstaller"
              },
              {
                "type": "null"
              }
            ],
            "description": "Windows only: the signed setup program, for servers where PowerShell scripts are not allowed. Null for Linux / Docker or when no verified build is published."
          },
          "install_steps": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "title": {
                  "type": "string"
                },
                "command": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "note": {
                  "type": "string"
                },
                "verify": {
                  "type": "string",
                  "description": "What to wait for afterwards (`connector_online`)."
                }
              }
            }
          },
          "alt_install": {
            "type": "object",
            "properties": {
              "docker": {
                "type": "string",
                "description": "`docker run` command with the enrolment token inline."
              }
            },
            "description": "Create answer only: alternative installs."
          },
          "setup_url": {
            "type": "null",
            "description": "Retired; always null."
          },
          "enrollment_jwt": {
            "type": [
              "string",
              "null"
            ],
            "description": "The connector's enrolment token itself (single use, valid `expires_at`). Prefer `install_command`; never paste it in chats or tickets."
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the enrolment token expires (7 days after creation). After that, remove and re-create the connector in the console."
          },
          "reveal_with": {
            "type": "object",
            "properties": {
              "method": {
                "type": "string"
              },
              "path": {
                "type": "string"
              }
            },
            "description": "`GET …/install` only: the call that makes a fresh install code."
          }
        },
        "required": [
          "connector"
        ]
      },
      "ConnectorHosting": {
        "type": "object",
        "properties": {
          "connector_id": {
            "type": "string"
          },
          "online": {
            "type": "boolean"
          },
          "enrolled": {
            "type": "boolean"
          },
          "expected_services": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConnectorHostedItem"
            },
            "description": "Every app, private network (and its DNS) or directory link this connector is set to host."
          },
          "hosted": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "service": {
                  "type": "string"
                },
                "kind": {
                  "type": "string"
                },
                "display_name": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "type": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "ha_hosts": {
                  "type": "integer"
                },
                "connection_id": {
                  "type": "string"
                },
                "private_network_id": {
                  "type": "string"
                },
                "link_hint": {
                  "type": "string"
                },
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "terminators": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "router": {
                        "type": "string",
                        "description": "Cloudraw edge location."
                      },
                      "precedence": {
                        "type": "string"
                      },
                      "cost": {
                        "type": "integer"
                      },
                      "created_at": {
                        "type": "string",
                        "format": "date-time"
                      }
                    }
                  }
                },
                "partial": {
                  "type": "boolean",
                  "description": "Held on fewer edge locations than expected."
                }
              }
            }
          },
          "missing": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Service names of items the connector should host but does not."
          },
          "missing_details": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConnectorHostedItem"
            }
          },
          "summary": {
            "type": "object",
            "properties": {
              "expected": {
                "type": "integer"
              },
              "hosted": {
                "type": "integer"
              },
              "missing": {
                "type": "integer"
              },
              "partial": {
                "type": "integer"
              },
              "terminators_total": {
                "type": "integer"
              },
              "expected_terminators_per_service": {
                "type": "integer"
              },
              "routers": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "router": {
                      "type": "string"
                    },
                    "connected": {
                      "type": [
                        "boolean",
                        "null"
                      ]
                    },
                    "terminators": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "checked_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the hosting data was read."
          }
        },
        "required": [
          "connector_id",
          "summary"
        ]
      },
      "ConnectorHostedItem": {
        "type": "object",
        "properties": {
          "service": {
            "type": "string",
            "description": "Internal service name."
          },
          "kind": {
            "type": "string",
            "enum": [
              "connection",
              "private_network",
              "private_network_dns",
              "directory"
            ]
          },
          "display_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "type": {
            "type": [
              "string",
              "null"
            ]
          },
          "ha_hosts": {
            "type": "integer",
            "description": "How many connectors host this item."
          },
          "connection_id": {
            "type": "string"
          },
          "private_network_id": {
            "type": "string"
          },
          "link_hint": {
            "type": "string",
            "description": "Path under `/v0/tenants/{tenant_id}/` that describes the item."
          },
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "service",
          "kind"
        ]
      },
      "ConnectorTrustState": {
        "type": "object",
        "properties": {
          "connector_id": {
            "type": "string"
          },
          "state": {
            "type": "string",
            "enum": [
              "trusted",
              "untrusted",
              "pending"
            ]
          },
          "reason": {
            "type": "string"
          },
          "source": {
            "type": "string",
            "enum": [
              "manual",
              "policy",
              "default",
              "removal"
            ]
          },
          "evaluated_at": {
            "type": "string",
            "format": "date-time"
          },
          "manual": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "trusted",
              "untrusted",
              null
            ]
          },
          "approved": {
            "type": "boolean"
          }
        },
        "required": [
          "connector_id",
          "state"
        ]
      },
      "ConnectorUpdateRequested": {
        "type": "object",
        "properties": {
          "connector_id": {
            "type": "string"
          },
          "requested_at": {
            "type": "string",
            "format": "date-time"
          },
          "target_version": {
            "type": [
              "string",
              "null"
            ],
            "description": "Version it will update to."
          },
          "note": {
            "type": "string"
          }
        },
        "required": [
          "connector_id",
          "requested_at"
        ]
      },
      "ConnectorUpdaterCommand": {
        "type": "object",
        "properties": {
          "connector_id": {
            "type": "string"
          },
          "os": {
            "type": [
              "string",
              "null"
            ],
            "description": "OS the connector reports."
          },
          "command": {
            "type": "string",
            "description": "The command for this connector's OS (Windows when the OS says so, else Linux). Shown once."
          },
          "windows": {
            "type": "string",
            "description": "Run in an Administrator PowerShell on the connector host."
          },
          "linux": {
            "type": "string",
            "description": "Run on the connector host (needs sudo)."
          },
          "note": {
            "type": "string"
          }
        },
        "required": [
          "connector_id",
          "command"
        ]
      },
      "ConnectorUpdateState": {
        "type": "object",
        "properties": {
          "connector_id": {
            "type": "string"
          },
          "update": {
            "$ref": "#/components/schemas/ConnectorUpdateStatus"
          }
        },
        "required": [
          "connector_id",
          "update"
        ]
      },
      "MaintenanceWindow": {
        "type": "object",
        "properties": {
          "days": {
            "type": "array",
            "items": {
              "type": "integer",
              "minimum": 0,
              "maximum": 6
            },
            "description": "Week days, 0 = Sunday … 6 = Saturday. Non-empty."
          },
          "start": {
            "type": "string",
            "description": "HH:MM, 24 h.",
            "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$"
          },
          "end": {
            "type": "string",
            "description": "HH:MM, 24 h. An end before the start wraps past midnight.",
            "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$"
          },
          "timezone": {
            "type": "string",
            "description": "IANA time zone, e.g. `Asia/Jerusalem`."
          }
        },
        "required": [
          "days",
          "start",
          "end",
          "timezone"
        ]
      },
      "UpdatePolicy": {
        "type": "object",
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "auto_window",
              "manual",
              "immediate"
            ],
            "description": "`auto_window` = install in the maintenance window; `manual` = only when an admin asks; `immediate` = as soon as a version is out. Applies to connectors and to the Cloudraw Connect app."
          },
          "channel": {
            "type": "string",
            "enum": [
              "stable",
              "beta"
            ],
            "description": "Release channel of the Cloudraw Connect app."
          },
          "maintenance_window": {
            "$ref": "#/components/schemas/MaintenanceWindow"
          },
          "allow_user_defer": {
            "type": "boolean",
            "description": "Users may postpone an app update."
          },
          "max_defers": {
            "type": "integer",
            "description": "How many times (0-20).",
            "minimum": 0,
            "maximum": 20
          },
          "target_version": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pin the Cloudraw Connect app to this version; null = latest on the channel."
          },
          "connector_mode": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "auto_window",
              "manual",
              "immediate",
              null
            ],
            "description": "Workspace default for CONNECTORS only; null = connectors follow `mode` too. A connector's own override (`PUT …/connectors/{connector_id}/update-mode`) wins over it."
          },
          "security_floor": {
            "type": "object",
            "properties": {
              "min_version": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "grace_hours": {
                "type": "integer"
              },
              "reason": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "set_at": {
                "type": "string",
                "format": "date-time"
              }
            },
            "description": "Minimum app version set by Cloudraw for a critical fix: older apps must update within `grace_hours`, whatever the policy. Not changeable by the workspace."
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_by": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "mode",
          "channel",
          "maintenance_window"
        ]
      },
      "UpdateCheck": {
        "type": "object",
        "properties": {
          "current_version": {
            "type": "string"
          },
          "available_version": {
            "type": "string"
          },
          "update_available": {
            "type": "boolean"
          },
          "should_update": {
            "type": "boolean"
          },
          "when": {
            "type": "string",
            "enum": [
              "none",
              "now",
              "window",
              "manual",
              "forced"
            ]
          },
          "deadline": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Set when `forced`: the latest time to install."
          },
          "forced": {
            "type": "boolean",
            "description": "Below the security floor."
          },
          "reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "mode": {
            "type": "string"
          },
          "channel": {
            "type": "string"
          },
          "maintenance_window": {
            "$ref": "#/components/schemas/MaintenanceWindow"
          },
          "allow_user_defer": {
            "type": "boolean"
          },
          "max_defers": {
            "type": "integer"
          }
        },
        "required": [
          "current_version",
          "available_version",
          "should_update",
          "when"
        ]
      },
      "ProvisioningToken": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "prefix": {
            "type": "string",
            "description": "First characters of the token, for recognition (`crwp_xxxxx…`)."
          },
          "created_by": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "revoked": {
            "type": "boolean"
          },
          "uses": {
            "type": "integer",
            "description": "Devices enrolled with it."
          },
          "max_uses": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Null = unlimited."
          }
        },
        "required": [
          "id",
          "name",
          "prefix",
          "expires_at",
          "revoked"
        ]
      },
      "ProvisioningTokenList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProvisioningToken"
            }
          },
          "next_page": {
            "type": "null",
            "description": "Always null: not paginated."
          }
        },
        "required": [
          "items"
        ]
      },
      "ProvisioningTokenCreated": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ProvisioningToken"
          },
          {
            "type": "object",
            "properties": {
              "token": {
                "type": "string",
                "description": "The provisioning token (`crwp_…`). Shown once; only a hash is kept."
              },
              "install": {
                "type": "object",
                "properties": {
                  "client_version": {
                    "type": "string",
                    "description": "Cloudraw Connect version to deploy."
                  },
                  "download_url": {
                    "type": "string",
                    "description": "Installer download."
                  },
                  "preset": {
                    "type": "object",
                    "properties": {
                      "schema": {
                        "type": "integer"
                      },
                      "workspace": {
                        "type": "string"
                      },
                      "signin": {
                        "type": "string"
                      },
                      "enrollment_url": {
                        "type": "string",
                        "description": "Carries the token: treat the preset file as a secret."
                      },
                      "managed_by": {
                        "type": "string"
                      }
                    },
                    "description": "Contents of the preset file to push to each machine."
                  },
                  "preset_path": {
                    "type": "string",
                    "description": "Where to stage the preset file before installing."
                  },
                  "installed_preset_path": {
                    "type": "string",
                    "description": "Where the installer puts it."
                  },
                  "windows": {
                    "type": "string",
                    "description": "Silent install command line."
                  },
                  "msi": {
                    "type": "null",
                    "description": "There is no MSI package."
                  },
                  "note": {
                    "type": "string"
                  },
                  "provision_endpoint": {
                    "type": "string"
                  }
                },
                "description": "How to deploy Cloudraw Connect silently with this token."
              }
            },
            "required": [
              "token",
              "install"
            ]
          }
        ]
      },
      "ConnectionGuideRef": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "section": {
            "type": [
              "string",
              "null"
            ]
          },
          "title": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "pdf_url": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "description": "A link to a setup guide."
      },
      "ConnectionSmbShare": {
        "type": "object",
        "properties": {
          "share": {
            "type": "string",
            "description": "Share name on the file server, 1-80 characters, without `\\ / : * ? \" < > |`."
          },
          "path": {
            "type": [
              "string",
              "null"
            ],
            "description": "Optional sub-folder inside the share (backslash separated, at most 200 characters, no `.` / `..`)."
          },
          "drive_letter": {
            "type": [
              "string",
              "null"
            ],
            "description": "Optional drive letter D-Z that Cloudraw Connect maps the share to. Unique per server.",
            "pattern": "^[D-Z]$"
          },
          "access": {
            "type": "string",
            "enum": [
              "rw",
              "ro"
            ],
            "description": "Read-write (default) or read-only (shown to people; the file server's own permissions decide in `direct` mode)."
          },
          "label": {
            "type": [
              "string",
              "null"
            ],
            "description": "Optional display label, at most 60 characters."
          },
          "unc": {
            "type": "string",
            "description": "Read only: the full `\\\\server\\share[\\path]` path."
          }
        },
        "required": [
          "share"
        ]
      },
      "ConnectionAllowedApp": {
        "type": "object",
        "properties": {
          "platform": {
            "type": "string",
            "enum": [
              "windows",
              "macos"
            ],
            "description": "Device platform this entry applies to (default `windows`). A device enforces only the entries of its platform."
          },
          "name": {
            "type": "string",
            "description": "Program file name (`mstsc.exe`) or, on macOS, the executable or `.app` name. 1-100 characters."
          },
          "publisher": {
            "type": "string",
            "description": "Signer name (Windows) or `Apple` / `Developer Name (TEAMID)` / bare TEAMID (macOS). Required in `strict` mode."
          },
          "identifier": {
            "type": "string",
            "description": "macOS only: the signing identifier, e.g. `com.microsoft.rdc.macos`."
          },
          "sha256": {
            "type": "string",
            "description": "Optional hash of the exact binary (64 hex characters).",
            "pattern": "^[0-9a-f]{64}$"
          },
          "thumbprint": {
            "type": "string",
            "description": "Windows only, optional: signer certificate thumbprint (SHA-1, 40 hex characters).",
            "pattern": "^[0-9a-f]{40}$"
          },
          "subject": {
            "type": "string",
            "description": "Optional signer subject (display name)."
          },
          "issuer": {
            "type": "string",
            "description": "Optional issuing CA (display name)."
          },
          "label": {
            "type": "string",
            "description": "Optional display label, at most 80 characters."
          }
        },
        "required": [
          "name"
        ]
      },
      "ConnectionAllowedApps": {
        "type": "object",
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "simple",
              "strict"
            ],
            "description": "`simple` matches the program name; `strict` also requires the signer (publisher). Default `simple`."
          },
          "enforce": {
            "type": "boolean",
            "description": "`false` (default) = report only: Cloudraw Connect reports programs that would be refused; `true` = refuse them."
          },
          "preset": {
            "type": "string",
            "enum": [
              "rdp",
              "browsers",
              "ssh"
            ],
            "description": "Write only: prepend a ready-made list (Remote Desktop clients, common browsers, SSH clients)."
          },
          "apps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConnectionAllowedApp"
            },
            "description": "At most 50 programs. Duplicates are dropped."
          },
          "alerts": {
            "type": "string",
            "enum": [
              "blocked",
              "all",
              "off"
            ],
            "description": "Which decisions raise an alert: only refusals (default), refusals and report-only \"would block\", or none."
          }
        },
        "description": "Allowed applications: only these programs on the device may open this app. Enforced on the device by Cloudraw Connect. `null` = no restriction."
      },
      "ConnectionRedirectionRule": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Rule name, 1-80 characters."
          },
          "when": {
            "type": "object",
            "properties": {
              "groups_any": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Group ids of this workspace."
              },
              "groups_none": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Group ids of this workspace."
              },
              "people_any": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Person ids of this workspace."
              },
              "countries_any": {
                "type": "array",
                "items": {
                  "type": "string",
                  "pattern": "^[A-Z]{2}$"
                },
                "description": "ISO country codes, e.g. `IL`."
              },
              "countries_none": {
                "type": "array",
                "items": {
                  "type": "string",
                  "pattern": "^[A-Z]{2}$"
                }
              }
            },
            "description": "At least one condition. All given conditions must match."
          },
          "set": {
            "type": "object",
            "properties": {
              "clipboard_in": {
                "type": "boolean"
              },
              "clipboard_out": {
                "type": "boolean"
              },
              "drives": {
                "type": "boolean"
              },
              "printers": {
                "type": "boolean"
              },
              "audio_out": {
                "type": "boolean"
              },
              "mic": {
                "type": "boolean"
              },
              "camera": {
                "type": "boolean"
              },
              "usb": {
                "type": "boolean"
              }
            },
            "description": "At least one redirection switch to override when the rule matches."
          }
        },
        "required": [
          "name",
          "when",
          "set"
        ],
        "description": "A conditional override of the redirection switches. Rules apply in order; a later match overrides an earlier one."
      },
      "ConnectionRemoteApp": {
        "type": "object",
        "properties": {
          "program": {
            "type": "string",
            "description": "A RemoteApp alias already published on the server (`||notepad`) or a program path (max 260 characters, no line breaks or `\"`)."
          },
          "dir": {
            "type": [
              "string",
              "null"
            ],
            "description": "Working directory, at most 260 characters."
          },
          "args": {
            "type": [
              "string",
              "null"
            ],
            "description": "Command-line arguments, at most 500 characters. With arguments, the server only allows exactly these."
          },
          "alias": {
            "type": "string",
            "description": "Read only: the RemoteApp alias Cloudraw registers on the server for a plain program path."
          },
          "launches_as": {
            "type": "string",
            "description": "Read only: what the remote desktop session starts."
          },
          "icon_source": {
            "type": "string",
            "enum": [
              "custom",
              "program"
            ],
            "description": "Read only: which icon Cloudraw Connect shows."
          },
          "program_icon": {
            "type": "boolean",
            "description": "Read only."
          },
          "feed_icon": {
            "type": "boolean",
            "description": "Read only."
          },
          "setup_done_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Read only: when the one-time server setup reported back (or was marked done)."
          },
          "setup": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "type": "object",
                "properties": {
                  "needed": {
                    "type": "boolean",
                    "description": "The one-time server setup has not reported back yet; the app cannot open until it has."
                  },
                  "done_at": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date-time"
                  },
                  "done_on": {
                    "type": [
                      "object",
                      "null"
                    ]
                  },
                  "error": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "method": {
                    "type": "string",
                    "enum": [
                      "connector",
                      "command"
                    ],
                    "description": "`connector`: the connector on that server does the setup itself. `command`: paste `one_liner` into PowerShell as Administrator on the server."
                  },
                  "one_liner": {
                    "type": "string",
                    "description": "PowerShell command that adds this one program to the server's RemoteApp allow-list. Treat as confidential: it contains a setup link."
                  },
                  "script_url": {
                    "type": "string"
                  },
                  "steps": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "guide": {
                    "oneOf": [
                      {
                        "type": "null"
                      },
                      {
                        "$ref": "#/components/schemas/ConnectionGuideRef"
                      }
                    ]
                  },
                  "why": {
                    "type": "string"
                  }
                },
                "description": "Read only. Present for a plain program path; `null` for a `||alias` the server already publishes."
              }
            ]
          }
        },
        "required": [
          "program"
        ],
        "description": "RemoteApp: the remote desktop opens only this program instead of the full desktop (RDP apps only)."
      },
      "Connection": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Application id."
          },
          "name": {
            "type": "string",
            "description": "Technical name (lower-case slug of the name you gave, at most 40 characters). Never changes."
          },
          "display_name": {
            "type": "string",
            "description": "The name people see. Change it with PATCH `display_name`."
          },
          "type": {
            "type": "string",
            "enum": [
              "rdp",
              "ssh",
              "vnc",
              "http",
              "https",
              "tcp",
              "db",
              "smb",
              "egress"
            ],
            "description": "Application type. See **Create an application** for what each type needs."
          },
          "host": {
            "type": "string",
            "description": "Target the connector reaches: host name or IP (for `egress`, the first host name)."
          },
          "port": {
            "type": "integer",
            "description": "Target port (445 for `smb`; for `egress`, the first port)."
          },
          "connector_id": {
            "type": "string",
            "description": "Primary hosting connector (= `connector_ids[0]`)."
          },
          "connector_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Every connector that hosts this application (1-5). Traffic fails over between them automatically."
          },
          "hostnames": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "`egress` only: the public host names devices send through the connector."
          },
          "ports": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "description": "`egress` only: the ports."
          },
          "egress": {
            "type": "boolean",
            "description": "`egress` only: always `true`."
          },
          "shares": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConnectionSmbShare"
            },
            "description": "`smb` only."
          },
          "protection_profile_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "`smb` only: the file protection profile applied in `gateway` mode."
          },
          "smb_mode": {
            "type": "string",
            "enum": [
              "direct",
              "gateway"
            ],
            "description": "`smb` only: `direct` = Cloudraw Connect reaches the server and its own permissions decide; `gateway` = protected: every file goes through the Cloudraw file gateway (scanned, profile enforced) and devices get no direct path."
          },
          "share_policy_enforced": {
            "type": "boolean",
            "description": "`smb` only: `true` in `gateway` mode."
          },
          "service_account": {
            "type": "object",
            "properties": {
              "configured": {
                "type": "boolean"
              },
              "username": {
                "type": "string"
              },
              "domain": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "set_at": {
                "type": "string",
                "format": "date-time"
              }
            },
            "required": [
              "configured"
            ],
            "description": "`smb` only: the account the file gateway signs in with (set in the console)."
          },
          "protection": {
            "type": [
              "object",
              "null"
            ],
            "description": "`smb` in `gateway` mode: `{ready, opens_in, missing[]}` — what is still missing (`service_account`, `gateway_path`)."
          },
          "share_check": {
            "type": [
              "object",
              "null"
            ],
            "description": "`smb` in `gateway` mode: the latest share check `{code, ok, at, stale}`."
          },
          "files_security": {
            "type": [
              "object",
              "null"
            ],
            "description": "`smb` only: open quarantine and blocked files in the last 24 hours."
          },
          "rdp_security": {
            "type": "string",
            "enum": [
              "any",
              "nla",
              "tls",
              "rdp"
            ],
            "description": "`rdp` only: security mode for browser sessions (`any` = negotiate)."
          },
          "rdp_domain": {
            "type": [
              "string",
              "null"
            ],
            "description": "`rdp` only: sign-in domain pre-filled in the browser portal (e.g. `CONTOSO`)."
          },
          "access_groups": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Legacy; access is granted by access rules (policy rules), not here."
          },
          "clientless": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Browser access is on (`true`). Same switch as `delivery.portal`."
          },
          "intercept": {
            "type": "string",
            "description": "The name devices use to reach the app: `<name>.<id>.cloudraw` for most types, the real server name for `smb`, the first host name for `egress`."
          },
          "status": {
            "type": "object",
            "properties": {
              "phase": {
                "type": "string"
              },
              "observed_at": {
                "type": "string",
                "format": "date-time"
              },
              "message": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "version": {
            "type": "integer",
            "description": "Increases on every change; send as `If-Match` on PATCH."
          },
          "created_by_integrator": {
            "type": [
              "object",
              "null"
            ],
            "description": "Set when an integrator (MSP) created the app on your behalf."
          },
          "delivery": {
            "type": "object",
            "properties": {
              "client": {
                "type": "boolean",
                "description": "Cloudraw Connect."
              },
              "portal": {
                "type": "boolean",
                "description": "Browser portal (= `clientless`)."
              },
              "rbi": {
                "type": "boolean"
              },
              "onetime_rdp": {
                "type": "boolean"
              },
              "native": {
                "type": "boolean",
                "description": "`rdp` only: \"Open in Remote Desktop app\" from the portal. Such sessions are not recorded."
              }
            },
            "description": "How people open the app."
          },
          "recording": {
            "type": "object",
            "properties": {
              "on": {
                "type": "boolean"
              },
              "required": {
                "type": "boolean",
                "description": "People may not open the app without recording."
              },
              "mode": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "groups": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "string"
                },
                "description": "Record only these groups; `null` = everyone."
              },
              "browser_only": {
                "type": "boolean",
                "description": "With recording on: every session goes through the recording gateway (`rdp`, `ssh`, `vnc` only); devices get no direct path."
              },
              "notice": {
                "type": "object",
                "properties": {
                  "on": {
                    "type": "boolean"
                  },
                  "mandatory": {
                    "type": "boolean",
                    "description": "Always `true`: recorded sessions always show the notice."
                  },
                  "text": {
                    "type": "string"
                  },
                  "custom": {
                    "type": "boolean"
                  },
                  "default_text": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "redirection": {
            "type": "object",
            "properties": {
              "clipboard_in": {
                "type": "boolean"
              },
              "clipboard_out": {
                "type": "boolean"
              },
              "drives": {
                "type": "boolean"
              },
              "printers": {
                "type": "boolean"
              },
              "audio_out": {
                "type": "boolean"
              },
              "mic": {
                "type": "boolean"
              },
              "camera": {
                "type": "boolean"
              },
              "usb": {
                "type": "boolean"
              }
            },
            "description": "Clipboard / drive / device redirection switches for remote sessions."
          },
          "reauth": {
            "type": "object",
            "properties": {
              "every_minutes": {
                "type": [
                  "integer",
                  "null"
                ],
                "minimum": 5,
                "maximum": 1440
              }
            },
            "description": "Ask people to sign in again every N minutes (`null` = off)."
          },
          "posture": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Device posture requirements (ids, at most 20). Stored; see `controls_enforcement`."
          },
          "appfw": {
            "type": "object",
            "properties": {
              "mode": {
                "type": "string",
                "enum": [
                  "off",
                  "monitor",
                  "enforce"
                ]
              },
              "allow": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "description": "Legacy per-app firewall field (stored only). Use `allowed_apps`."
          },
          "redirection_rules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConnectionRedirectionRule"
            }
          },
          "allowed_apps": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ConnectionAllowedApps"
              }
            ]
          },
          "remote_app": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ConnectionRemoteApp"
              }
            ],
            "description": "`rdp` only (absent for other types)."
          },
          "gateway_only": {
            "type": "object",
            "properties": {
              "on": {
                "type": "boolean"
              },
              "reason": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "protected_file_server",
                  "recorded_browser_only",
                  null
                ]
              }
            },
            "description": "The app is reachable only through a Cloudraw gateway."
          },
          "guides": {
            "type": "object",
            "properties": {
              "app": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/ConnectionGuideRef"
                  }
                ]
              },
              "allowed_apps": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/ConnectionGuideRef"
                  }
                ]
              },
              "alerts": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/ConnectionGuideRef"
                  }
                ]
              }
            }
          },
          "icon": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "url": {
                "type": "string",
                "description": "Relative to the workspace URL."
              }
            },
            "description": "The app's custom icon, if set in the console."
          },
          "browser": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "supported": {
                "type": "boolean"
              },
              "ready": {
                "type": "boolean"
              },
              "error": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "opens": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "remote_app",
                  "desktop",
                  "terminal",
                  "screen",
                  null
                ]
              }
            },
            "description": "With browser access on: whether the app can open in the browser now."
          },
          "controls_enforcement": {
            "type": "object",
            "properties": {
              "delivery": {
                "type": "string",
                "enum": [
                  "enforced",
                  "stored",
                  "partial:browser_sessions_only",
                  "partial:client_min_version",
                  "partial:report_only"
                ]
              },
              "recording": {
                "type": "string",
                "enum": [
                  "enforced",
                  "stored",
                  "partial:browser_sessions_only",
                  "partial:client_min_version",
                  "partial:report_only"
                ]
              },
              "redirection": {
                "type": "string",
                "enum": [
                  "enforced",
                  "stored",
                  "partial:browser_sessions_only",
                  "partial:client_min_version",
                  "partial:report_only"
                ]
              },
              "reauth": {
                "type": "string",
                "enum": [
                  "enforced",
                  "stored",
                  "partial:browser_sessions_only",
                  "partial:client_min_version",
                  "partial:report_only"
                ]
              },
              "posture": {
                "type": "string",
                "enum": [
                  "enforced",
                  "stored",
                  "partial:browser_sessions_only",
                  "partial:client_min_version",
                  "partial:report_only"
                ]
              },
              "appfw": {
                "type": "string",
                "enum": [
                  "enforced",
                  "stored",
                  "partial:browser_sessions_only",
                  "partial:client_min_version",
                  "partial:report_only"
                ]
              },
              "allowed_apps": {
                "type": "string",
                "enum": [
                  "enforced",
                  "stored",
                  "partial:browser_sessions_only",
                  "partial:client_min_version",
                  "partial:report_only"
                ]
              }
            },
            "description": "Where each control is applied today: `enforced`, `stored` (saved, not applied yet) or `partial:<where>`."
          }
        },
        "required": [
          "id",
          "name",
          "display_name",
          "type",
          "host",
          "port",
          "connector_id",
          "connector_ids",
          "version"
        ]
      },
      "ConnectionList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Connection"
            }
          },
          "next_page": {
            "type": "null",
            "description": "Always `null`: the list is not paginated."
          }
        },
        "required": [
          "items"
        ]
      },
      "ConnectionCreate": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name, 1-80 characters, without `< > \" ' ` & \\` or quote marks. Must not equal `pn-<name>` of a private network."
          },
          "type": {
            "type": "string",
            "enum": [
              "rdp",
              "ssh",
              "vnc",
              "http",
              "https",
              "tcp",
              "db",
              "smb",
              "egress"
            ],
            "description": "Application type. `smb` = Windows file server; `egress` = public website / SaaS reached from the connector's public IP; `rdp`, `ssh`, `vnc` can also open in the browser. Any other type is a plain TCP application on `host:port`."
          },
          "host": {
            "type": "string",
            "description": "Required except for `egress`. Host name or IP the connector reaches. For `smb`: the file server name only (not a `\\\\server\\share` path); devices keep using that real name."
          },
          "port": {
            "type": "integer",
            "description": "Required except for `smb` (always 445) and `egress`.",
            "minimum": 1,
            "maximum": 65535
          },
          "connector_id": {
            "type": "string",
            "description": "Required. Primary hosting connector."
          },
          "connector_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Optional extra hosting connectors for failover (at most 5 in total, including `connector_id`)."
          },
          "hostnames": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "`egress` only, required: 1-20 public host names (`*.example.com` wildcards allowed, scoped to a domain). They must resolve to public addresses; Cloudraw names are refused."
          },
          "ports": {
            "type": "array",
            "items": {
              "type": "integer",
              "minimum": 1,
              "maximum": 65535
            },
            "description": "`egress` only: 1-10 ports, default `[443, 80]`."
          },
          "shares": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConnectionSmbShare"
            },
            "description": "`smb` only, required: 1-20 shares."
          },
          "smb_mode": {
            "type": "string",
            "enum": [
              "direct",
              "gateway"
            ],
            "description": "`smb` only. Default `direct`."
          },
          "protection_profile_id": {
            "type": "string",
            "description": "`smb` only: an existing file protection profile id."
          },
          "remote_app": {
            "$ref": "#/components/schemas/ConnectionRemoteApp"
          },
          "clientless": {
            "type": "boolean",
            "description": "Turn on browser access right away."
          }
        },
        "required": [
          "name",
          "type",
          "connector_id"
        ]
      },
      "ConnectionUpdate": {
        "type": "object",
        "properties": {
          "display_name": {
            "type": "string",
            "description": "New display name, 1-80 characters, without `< > \" ' ` & \\` or quote marks. (`name` never changes.)"
          },
          "host": {
            "type": "string",
            "description": "New target host (1-253 characters). For `smb`, the file server name (moves the intercept too)."
          },
          "port": {
            "type": "integer",
            "description": "New target port. Not for `smb` or `egress`.",
            "minimum": 1,
            "maximum": 65535
          },
          "hostnames": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "`egress` only: replaces the host names (1-20)."
          },
          "ports": {
            "type": "array",
            "items": {
              "type": "integer",
              "minimum": 1,
              "maximum": 65535
            },
            "description": "`egress` only: replaces the ports (1-10)."
          },
          "connector_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Replaces the hosting connectors (1-5). The first one becomes `connector_id`."
          },
          "clientless": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Browser access on / off."
          },
          "delivery": {
            "type": "object",
            "properties": {
              "client": {
                "type": "boolean"
              },
              "portal": {
                "type": "boolean",
                "description": "Same as `clientless`."
              },
              "rbi": {
                "type": "boolean"
              },
              "onetime_rdp": {
                "type": "boolean"
              },
              "native": {
                "type": "boolean",
                "description": "`rdp` only. Refused while recording is required or browser-only."
              }
            },
            "description": "Only the keys you send change."
          },
          "recording": {
            "type": "object",
            "properties": {
              "on": {
                "type": "boolean"
              },
              "required": {
                "type": "boolean",
                "description": "Ignored (set to `false`) while `on` is false."
              },
              "mode": {
                "type": [
                  "string",
                  "null"
                ],
                "maxLength": 40
              },
              "groups": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "string"
                },
                "description": "Record only these groups; `null` or `[]` = everyone."
              },
              "browser_only": {
                "type": "boolean",
                "description": "`rdp`, `ssh`, `vnc` only. Turns browser access on if it was off."
              },
              "notice": {
                "type": [
                  "object",
                  "null"
                ],
                "properties": {
                  "text": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 300
                  }
                },
                "description": "Custom notice text (`null` or empty = the default). The notice itself cannot be switched off."
              }
            },
            "description": "Only the keys you send change."
          },
          "redirection": {
            "type": "object",
            "properties": {
              "clipboard_in": {
                "type": "boolean"
              },
              "clipboard_out": {
                "type": "boolean"
              },
              "drives": {
                "type": "boolean"
              },
              "printers": {
                "type": "boolean"
              },
              "audio_out": {
                "type": "boolean"
              },
              "mic": {
                "type": "boolean"
              },
              "camera": {
                "type": "boolean"
              },
              "usb": {
                "type": "boolean"
              }
            },
            "description": "Only the keys you send change. Unknown keys and non-boolean values are refused."
          },
          "redirection_rules": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/ConnectionRedirectionRule"
            },
            "maxItems": 20,
            "description": "Replaces the list; `null` clears it."
          },
          "reauth": {
            "type": "object",
            "properties": {
              "every_minutes": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Clamped to 5-1440; `null` = off."
              }
            }
          },
          "posture": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Replaces the list (at most 20 kept)."
          },
          "appfw": {
            "type": "object",
            "properties": {
              "mode": {
                "type": "string",
                "enum": [
                  "off",
                  "monitor",
                  "enforce"
                ]
              },
              "allow": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "description": "Legacy. An unknown `mode` is ignored."
          },
          "allowed_apps": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ConnectionAllowedApps"
              }
            ],
            "description": "Replaces the allowed-applications policy; `null` removes it."
          },
          "remote_app": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ConnectionRemoteApp"
              }
            ],
            "description": "`rdp` only. `null` = full desktop. A new program mints a new setup command."
          },
          "remote_app_setup_done": {
            "type": "boolean",
            "description": "`rdp` only: mark the one-time server setup as done (you did it by hand) or not done."
          },
          "rdp_security": {
            "type": "string",
            "enum": [
              "any",
              "nla",
              "tls",
              "rdp"
            ],
            "description": "`rdp` only."
          },
          "rdp_domain": {
            "type": [
              "string",
              "null"
            ],
            "description": "`rdp` only: domain like `CONTOSO` (letters, digits, `-`, `.`, max 64), or `null`."
          },
          "shares": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConnectionSmbShare"
            },
            "description": "`smb` only: replaces the shares (1-20)."
          },
          "smb_mode": {
            "type": "string",
            "enum": [
              "direct",
              "gateway"
            ],
            "description": "`smb` only."
          },
          "protection_profile_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "`smb` only; `null` clears it."
          }
        },
        "description": "Send only what you change."
      },
      "PrivateNetwork": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "connector_id": {
            "type": "string",
            "description": "Primary hosting connector (cannot be changed)."
          },
          "connector_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Every hosting connector (1-5)."
          },
          "cidrs": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IPv4 ranges devices reach through the connector."
          },
          "dns_zones": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "DNS suffixes of this environment (e.g. `corp.example.local`); subdomains are included."
          },
          "dns_servers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Your internal DNS servers (inside `cidrs`)."
          },
          "dns_mode": {
            "type": "string",
            "enum": [
              "overlay",
              "forward"
            ],
            "description": "`overlay`: the connector resolves names in `dns_zones` (address records only). `forward`: devices send DNS for the zones to `dns_servers` through the tunnel (full DNS, needed for a domain join)."
          },
          "translate": {
            "type": "boolean",
            "description": "Address translation is on (for ranges that overlap the devices' own networks)."
          },
          "translated_cidr": {
            "type": [
              "string",
              "null"
            ],
            "description": "With translation on: the range devices use instead of `cidrs[0]` (from 100.65.0.0/16)."
          },
          "guides": {
            "type": "object",
            "properties": {
              "network": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/ConnectionGuideRef"
                  }
                ]
              },
              "cidr": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/ConnectionGuideRef"
                  }
                ]
              },
              "translate": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/ConnectionGuideRef"
                  }
                ]
              }
            }
          },
          "protocols": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "tcp",
                "udp"
              ]
            }
          },
          "port_ranges": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PrivateNetworkPortRange"
            }
          },
          "require_trusted_device": {
            "type": "boolean",
            "description": "Access rules for this network also require a trusted device (default `true`)."
          },
          "access_rule_count": {
            "type": "integer",
            "description": "Access rules that grant this network."
          },
          "notes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Plain-English hints about the DNS setup."
          },
          "dns_findings": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "kind": {
                  "type": "string",
                  "enum": [
                    "zone",
                    "dns_server"
                  ]
                },
                "value": {
                  "type": "string"
                },
                "class": {
                  "type": "string",
                  "enum": [
                    "verified",
                    "operator",
                    "legacy",
                    "refused"
                  ]
                }
              }
            },
            "description": "Zones / DNS servers outside private address space, and why they are allowed."
          },
          "status": {
            "type": "object",
            "properties": {
              "phase": {
                "type": "string",
                "enum": [
                  "provisioning",
                  "ready",
                  "degraded"
                ]
              },
              "observed_at": {
                "type": "string",
                "format": "date-time"
              },
              "message": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "version": {
            "type": "integer",
            "description": "Increases on every change; send as `If-Match` on PATCH."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "name",
          "connector_id",
          "cidrs",
          "version"
        ]
      },
      "PrivateNetworkPortRange": {
        "type": "object",
        "properties": {
          "low": {
            "type": "integer",
            "minimum": 1,
            "maximum": 65535
          },
          "high": {
            "type": "integer",
            "minimum": 1,
            "maximum": 65535
          }
        },
        "required": [
          "low",
          "high"
        ],
        "description": "`low` <= `high`."
      },
      "PrivateNetworkList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PrivateNetwork"
            }
          },
          "next_page": {
            "type": "null",
            "description": "Always `null`: the list is not paginated."
          }
        },
        "required": [
          "items"
        ]
      },
      "PrivateNetworkCreate": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "1-64 characters, at least one letter or digit. Unique in the workspace.",
            "maxLength": 64
          },
          "connector_id": {
            "type": "string",
            "description": "Hosting connector."
          },
          "connector_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Optional extra hosting connectors (1-5 in total)."
          },
          "cidrs": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "1-32 IPv4 CIDR ranges, `/8` or narrower, host bits zero, not overlapping each other or another private network. Loopback, link-local, multicast and 100.64.0.0/10 are refused."
          },
          "dns_zones": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Up to 10 zones. A private suffix (`.local`, `.internal`, `.lan`, `.corp`, `home.arpa`, private reverse zones…) or a domain this workspace has verified by DNS TXT. Not wildcards."
          },
          "dns_servers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Up to 4 private IPv4 addresses, each inside one of `cidrs`."
          },
          "protocols": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "tcp",
                "udp"
              ]
            },
            "description": "Default `[\"tcp\",\"udp\"]`."
          },
          "port_ranges": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PrivateNetworkPortRange"
            },
            "description": "1-20 ranges. Default all ports."
          },
          "require_trusted_device": {
            "type": "boolean",
            "description": "Default `true`."
          },
          "translate": {
            "type": "boolean",
            "description": "Address translation: needs exactly one range in `cidrs`, between /16 and /30."
          }
        },
        "required": [
          "name",
          "connector_id",
          "cidrs"
        ]
      },
      "PrivateNetworkUpdate": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 64
          },
          "connector_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Replaces the hosting connectors (1-5)."
          },
          "cidrs": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "dns_zones": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "dns_servers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "protocols": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "tcp",
                "udp"
              ]
            }
          },
          "port_ranges": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PrivateNetworkPortRange"
            }
          },
          "require_trusted_device": {
            "type": "boolean"
          },
          "translate": {
            "type": "boolean"
          }
        },
        "description": "Same rules as on create. `connector_id` cannot be changed; unknown fields are refused."
      },
      "ConditionNode": {
        "type": "object",
        "description": "One node of a condition tree: a group node (`op` + `children`) or a leaf (`type` + `operator` + `value`). See the table in **Create an access rule**.",
        "properties": {
          "op": {
            "type": "string",
            "enum": [
              "and",
              "or"
            ],
            "description": "Group node: how the children combine."
          },
          "negate": {
            "type": "boolean",
            "description": "Group node: `true` on an `or` node marks an exclude list (\"anyone except …\"). Not enforceable in access rules."
          },
          "children": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConditionNode"
            },
            "description": "Group node: the child nodes."
          },
          "type": {
            "type": "string",
            "enum": [
              "group",
              "person",
              "device",
              "posture",
              "network",
              "time",
              "mfa",
              "app",
              "attribute"
            ],
            "description": "Leaf: what is tested."
          },
          "field": {
            "type": "string",
            "description": "Leaf: the sub-field for `posture`, `network`, `mfa` (and the attribute name for `attribute`)."
          },
          "operator": {
            "type": "string",
            "description": "Leaf: the operator (depends on `type` / `field`)."
          },
          "value": {
            "description": "Leaf: the operand — a list of ids, a boolean, a list of codes, `{tz,start,end}`, `{from,to}`, …"
          },
          "resolved_groups": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "display_name": {
                  "type": "string"
                },
                "state": {
                  "type": "string"
                }
              }
            },
            "description": "Read-only, in `form_view`: the groups a `group` leaf names."
          },
          "resolved_people": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "display_name": {
                  "type": "string"
                },
                "email": {
                  "type": "string"
                },
                "state": {
                  "type": "string"
                }
              }
            },
            "description": "Read-only, in `form_view`: the people a `person` leaf names."
          },
          "resolved_devices": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "display_name": {
                  "type": "string"
                },
                "state": {
                  "type": "string"
                }
              }
            },
            "description": "Read-only, in `form_view`: the devices a `device` leaf names."
          }
        },
        "example": {
          "op": "and",
          "children": [
            {
              "type": "group",
              "operator": "in",
              "value": [
                "g3k9d0s7aa"
              ]
            },
            {
              "type": "posture",
              "field": "disk_encrypted",
              "operator": "eq",
              "value": true
            }
          ]
        }
      },
      "RuleTarget": {
        "type": "object",
        "properties": {
          "service_id": {
            "type": "string",
            "description": "An app (connection) id in this workspace."
          },
          "private_network_id": {
            "type": "string",
            "description": "A private network id in this workspace. Private networks also require a trusted device unless the network is set otherwise."
          },
          "service_role": {
            "type": "string",
            "description": "Advanced: an app role of this workspace (it starts with your workspace id and a dash). Cannot name private networks."
          }
        },
        "description": "What the rule grants. Exactly one of the three fields."
      },
      "RuleFormView": {
        "type": "object",
        "properties": {
          "include": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConditionNode"
            },
            "description": "Who the rule applies to (one OR list): group / person / device / simple attribute leaves, decorated with `resolved_groups`, `resolved_people` or `resolved_devices`."
          },
          "require": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConditionNode"
            },
            "description": "Conditions that must all hold (posture, time, mfa, attribute)."
          },
          "exclude": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConditionNode"
            },
            "description": "Who is excluded (the negated OR list)."
          }
        },
        "required": [
          "include",
          "require",
          "exclude"
        ],
        "description": "The rule read as the console's simple form: Include / Require / Except. Present only when `form_representable` is true."
      },
      "PolicyRule": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Access rule id."
          },
          "name": {
            "type": "string",
            "description": "1-128 characters."
          },
          "effect": {
            "type": "string",
            "enum": [
              "allow",
              "deny"
            ]
          },
          "enabled": {
            "type": "boolean",
            "description": "False when the rule is turned off: it then has no effect at all. Default true."
          },
          "target": {
            "$ref": "#/components/schemas/RuleTarget"
          },
          "match": {
            "$ref": "#/components/schemas/ConditionNode"
          },
          "enforced": {
            "type": "boolean",
            "description": "True when the rule is live at the edge. An `allow` rule that is not enforced grants nothing. A `deny` rule is enforced when it removes access at the edge for everyone it matches."
          },
          "enforcement_reason": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why the rule is not enforced (null when it is)."
          },
          "enforcement_status": {
            "type": "string",
            "enum": [
              "active_at_edge",
              "not_at_edge",
              "fail_closed",
              "off"
            ],
            "description": "`fail_closed` (deny rules only): a condition can't be checked yet, so the deny is applied to everyone it could match. `off`: the rule is turned off."
          },
          "traffic_effect": {
            "type": "string",
            "description": "Plain-English summary of what the rule does to traffic right now."
          },
          "form_representable": {
            "type": "boolean",
            "description": "True when the console can show and edit the rule in its simple form."
          },
          "form_view": {
            "$ref": "#/components/schemas/RuleFormView"
          },
          "version": {
            "type": "integer",
            "description": "Increases on every change. Send it as `If-Match` on PATCH and DELETE."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "name",
          "effect",
          "target",
          "match",
          "enforced",
          "version"
        ]
      },
      "PolicyRuleEvaluation": {
        "type": "object",
        "properties": {
          "compiles": {
            "type": "boolean",
            "description": "True when the draft is valid."
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "path": {
                  "type": "string",
                  "description": "e.g. `match.children[1].value`"
                },
                "message": {
                  "type": "string"
                }
              }
            },
            "description": "Validation errors (empty when it compiles)."
          },
          "enforced": {
            "type": "boolean",
            "description": "Whether the draft, saved as an `allow` rule, would be live at the edge. Needs `target`."
          },
          "enforcement_reason": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why not, e.g. `no target` or `does not compile`."
          },
          "match_count": {
            "type": "integer",
            "description": "Devices the draft would grant right now (needs `target`)."
          },
          "sample_matches": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "device_id": {
                  "type": "string"
                },
                "device_name": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "person": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Person name or e-mail."
                }
              }
            },
            "description": "Up to 5 of those devices."
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "form_representable": {
            "type": "boolean"
          },
          "form_view": {
            "$ref": "#/components/schemas/RuleFormView"
          }
        },
        "required": [
          "compiles",
          "errors",
          "enforced",
          "match_count"
        ]
      },
      "ConditionCatalog": {
        "type": "object",
        "properties": {
          "generated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When this catalog version was published."
          },
          "types": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "description": "Leaf `type`."
                },
                "value_type": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "note": {
                  "type": "string"
                },
                "operators": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "operator": {
                        "type": "string"
                      },
                      "arity": {
                        "type": "string",
                        "description": "`scalar`, `list`, `range`, `window`, `day_set`."
                      },
                      "value_type": {
                        "type": "string"
                      },
                      "note": {
                        "type": "string"
                      }
                    }
                  }
                },
                "fields": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "field": {
                        "type": "string"
                      },
                      "operators": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      "value_type": {
                        "type": "string"
                      },
                      "note": {
                        "type": "string"
                      },
                      "values": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "label": {
                              "type": "string"
                            }
                          }
                        },
                        "description": "Allowed ids with labels (e.g. OS families, second-step methods)."
                      }
                    }
                  }
                },
                "evaluated": {
                  "description": "Where the leaf is evaluated (`false` = stored but not evaluated yet)."
                },
                "enforced_at_edge": {
                  "type": "boolean",
                  "description": "False when the leaf cannot be enforced in an access rule."
                }
              }
            }
          }
        },
        "required": [
          "types"
        ],
        "description": "Every condition type, field and operator the rule validator accepts, with notes on what is enforced."
      },
      "TrustVerdict": {
        "type": "object",
        "properties": {
          "state": {
            "type": "string",
            "enum": [
              "trusted",
              "untrusted"
            ]
          },
          "reason": {
            "type": "string",
            "description": "Plain-English reason."
          },
          "unmet": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "kind": {
                  "type": "string",
                  "description": "e.g. `posture`, `group`, `network`, `reauth`."
                },
                "field": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "op": {
                  "type": "string"
                },
                "value": {},
                "got": {
                  "description": "What the device reported (null = not reported)."
                },
                "text": {
                  "type": "string",
                  "description": "Plain-English explanation."
                }
              }
            },
            "description": "The conditions the device fails (from the first trust rule tried)."
          },
          "evaluated_at": {
            "type": "string",
            "format": "date-time"
          },
          "source": {
            "type": "string",
            "enum": [
              "rule",
              "manual",
              "default",
              "policy"
            ],
            "description": "`rule` = trust rules decided; `manual` = an admin marked the device; `default` = no trust rules exist; `policy` = re-authentication or suspension."
          },
          "matched_rule": {
            "type": "string",
            "description": "The trust rule that trusted the device (when `source` is `rule` and the state is `trusted`)."
          }
        },
        "required": [
          "state",
          "reason",
          "source"
        ]
      },
      "AccessExplanation": {
        "type": "object",
        "properties": {
          "device": {
            "type": "string",
            "description": "Device id."
          },
          "device_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "person": {
            "type": [
              "string",
              "null"
            ],
            "description": "Person name."
          },
          "groups": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Group ids of the device's person."
          },
          "connection": {
            "type": "string",
            "description": "App id (when an app was checked)."
          },
          "private_network": {
            "type": "string",
            "description": "Private network id (when a private network was checked)."
          },
          "resource_kind": {
            "type": "string",
            "enum": [
              "connection",
              "private_network"
            ]
          },
          "resource_name": {
            "type": "string"
          },
          "verdict": {
            "type": "string",
            "enum": [
              "REACHABLE",
              "BLOCKED"
            ]
          },
          "reachable": {
            "type": "boolean"
          },
          "blocked_at": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "trust",
              "access",
              null
            ],
            "description": "The gate that blocks (null when reachable)."
          },
          "gates": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "gate": {
                  "type": "string",
                  "enum": [
                    "trust",
                    "access"
                  ]
                },
                "label": {
                  "type": "string"
                },
                "pass": {
                  "type": "boolean"
                },
                "detail": {
                  "type": "string",
                  "description": "Plain-English explanation."
                },
                "trust": {
                  "$ref": "#/components/schemas/TrustVerdict"
                },
                "admission_enforced": {
                  "type": "boolean",
                  "description": "Trust gate: untrusted devices are kept off the network entirely."
                },
                "matched_rule": {
                  "type": [
                    "object",
                    "null"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    }
                  },
                  "description": "Access gate: the rule that grants access."
                },
                "considered": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "rule": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      },
                      "enforced": {
                        "type": "boolean"
                      },
                      "enforcement_reason": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "grants": {
                        "type": "boolean"
                      },
                      "missing_posture": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "description": "Device checks the device fails for this rule; `!field` = must be false."
                      }
                    }
                  },
                  "description": "Access gate: every allow rule targeting the resource."
                }
              }
            },
            "description": "Trust gate first, then access gate."
          }
        },
        "required": [
          "device",
          "verdict",
          "reachable",
          "gates"
        ]
      },
      "TrustRule": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Trust rule id."
          },
          "name": {
            "type": "string",
            "description": "1-128 characters."
          },
          "match": {
            "$ref": "#/components/schemas/ConditionNode"
          },
          "enabled": {
            "type": "boolean",
            "description": "Disabled rules are ignored."
          },
          "form_representable": {
            "type": "boolean"
          },
          "form_view": {
            "$ref": "#/components/schemas/RuleFormView"
          },
          "version": {
            "type": "integer",
            "description": "Send as `If-Match` on PATCH and DELETE."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "name",
          "match",
          "enabled",
          "version"
        ]
      },
      "TrustRuleDevice": {
        "type": "object",
        "properties": {
          "device_id": {
            "type": "string"
          },
          "device_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "person": {
            "type": [
              "string",
              "null"
            ]
          },
          "os": {
            "type": [
              "string",
              "null"
            ]
          },
          "trust_now": {
            "type": "string",
            "enum": [
              "trusted",
              "untrusted"
            ]
          },
          "trust_source": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          }
        }
      },
      "TrustRuleEvaluation": {
        "type": "object",
        "properties": {
          "compiles": {
            "type": "boolean"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "path": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          },
          "form_representable": {
            "type": "boolean"
          },
          "form_view": {
            "$ref": "#/components/schemas/RuleFormView"
          },
          "match_count": {
            "type": "integer",
            "description": "Devices the draft matches right now."
          },
          "sample_matches": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrustRuleDevice"
            },
            "description": "Up to 10 of them."
          },
          "would_gain": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrustRuleDevice"
            },
            "description": "Devices that would become trusted with this draft (other enabled rules still count)."
          },
          "would_lose": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrustRuleDevice"
            },
            "description": "Devices that would stop being trusted (only when `replaces` names a rule being edited)."
          }
        },
        "required": [
          "compiles",
          "errors",
          "match_count",
          "would_gain",
          "would_lose"
        ]
      },
      "PostureProfile": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "description": "Up to 80 characters."
          },
          "conditions": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "disk_encrypted",
                "antivirus_on",
                "antivirus_present",
                "edr_present",
                "firewall_on",
                "os_up_to_date",
                "screen_lock",
                "domain_or_entra_joined",
                "managed_baseline",
                "os_is_windows",
                "os_is_macos"
              ]
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "version": {
            "type": "integer"
          }
        },
        "required": [
          "id",
          "name",
          "conditions"
        ]
      },
      "JitRequest": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "person",
              "vendor",
              "admin"
            ],
            "description": "`person` = one of your people asked from Cloudraw Connect; `vendor` = an outside supplier through an invite link; `admin` = filed by an admin."
          },
          "subject": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "email": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "vendor": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Supplier company (null for your own people)."
              }
            }
          },
          "connection_id": {
            "type": "string",
            "description": "The app asked for."
          },
          "resource_name": {
            "type": "string"
          },
          "mode": {
            "type": "string",
            "description": "Always `access` today."
          },
          "window_hours": {
            "type": "integer",
            "description": "Requested duration, 1-24 hours (capped by the JIT policy)."
          },
          "reason": {
            "type": "string"
          },
          "sponsor": {
            "type": "string",
            "description": "The internal person who vouches for the request."
          },
          "risk": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "low",
              "med",
              "high",
              null
            ]
          },
          "device_posture": {
            "type": [
              "string",
              "null"
            ]
          },
          "state": {
            "type": "string",
            "enum": [
              "pending_email",
              "pending",
              "approved",
              "denied",
              "cancelled",
              "expired"
            ],
            "description": "`pending_email` = the vendor has not confirmed their e-mail yet; only `pending` requests can be decided."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "decided_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "decided_by": {
            "type": [
              "string",
              "null"
            ]
          },
          "decided_note": {
            "type": [
              "string",
              "null"
            ]
          },
          "grant_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "The grant created on approval."
          },
          "requested_by": {
            "type": [
              "string",
              "null"
            ]
          },
          "via_invite": {
            "type": [
              "string",
              "null"
            ],
            "description": "The invite link used (vendor requests)."
          },
          "device": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "os": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "description": "The device that asked, as reported."
          },
          "email_verified": {
            "type": "boolean"
          }
        },
        "required": [
          "id",
          "kind",
          "subject",
          "connection_id",
          "state"
        ]
      },
      "JitGrant": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "request_id": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "person",
              "vendor"
            ]
          },
          "subject": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "email": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "vendor": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "connection_id": {
            "type": "string"
          },
          "resource_name": {
            "type": "string"
          },
          "approver": {
            "type": [
              "string",
              "null"
            ]
          },
          "window_hours": {
            "type": "integer"
          },
          "started_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "state": {
            "type": "string",
            "enum": [
              "active",
              "revoke_pending",
              "revoked",
              "expired"
            ],
            "description": "`revoke_pending` = no longer usable from Cloudraw's side; removal is being retried."
          },
          "recording": {
            "type": "boolean",
            "description": "Recording was requested for this grant (stored; see `controls_enforcement`)."
          },
          "mfa": {
            "type": "boolean",
            "description": "A second step was required for this grant (stored; see `controls_enforcement`)."
          },
          "ended_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "ended_reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "device_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Person grants: the device that gets access."
          },
          "claimed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "claim_pending": {
            "type": "boolean",
            "description": "Vendor grants: the vendor has not yet claimed their one-time credential."
          },
          "controls_enforcement": {
            "type": "object",
            "properties": {
              "recording": {
                "type": "string"
              },
              "mfa": {
                "type": "string"
              }
            },
            "description": "`stored` = the setting is recorded but not enforced yet."
          }
        },
        "required": [
          "id",
          "request_id",
          "connection_id",
          "state",
          "expires_at"
        ]
      },
      "JitApproval": {
        "allOf": [
          {
            "$ref": "#/components/schemas/JitGrant"
          },
          {
            "type": "object",
            "properties": {
              "enrollment_jwt": {
                "type": "string",
                "description": "Only for requests an admin filed for a vendor: the one-time credential for the vendor's Cloudraw Connect. Shown once."
              }
            }
          }
        ]
      },
      "JitPolicy": {
        "type": "object",
        "properties": {
          "sponsor_required": {
            "type": "boolean",
            "description": "An internal sponsor must vouch for each request."
          },
          "record_by_default": {
            "type": "boolean",
            "description": "New grants are marked for recording."
          },
          "block_unmanaged": {
            "type": "boolean",
            "description": "Person requests can only be approved for trusted devices, and the grant also requires the device to stay trusted."
          },
          "max_window_hours": {
            "type": "integer",
            "description": "Longest grant, 1-24 hours."
          },
          "require_mfa": {
            "type": "boolean",
            "description": "New grants are marked as requiring a second step."
          },
          "employee_requests": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "Your own people may request access from Cloudraw Connect."
              },
              "connection_ids": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "string"
                },
                "description": "Apps they may request; null = every app."
              }
            }
          },
          "version": {
            "type": "integer"
          }
        }
      },
      "LiveSession": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Session id. `ovl_…` = a live connection seen on the Cloudraw network right now (can be ended); `ses_…` = a session reported by the portal."
          },
          "source": {
            "type": "string",
            "enum": [
              "overlay",
              "ingest"
            ],
            "description": "`overlay` = observed live on the Cloudraw network; `ingest` = reported by the portal."
          },
          "state": {
            "type": "string",
            "enum": [
              "active"
            ],
            "description": "Always `active` in this list."
          },
          "user": {
            "type": [
              "string",
              "null"
            ],
            "description": "Display name (or e-mail) of the person; for vendor access \"<name> (<vendor>)\"; for browser sessions the signed-in person, or \"Browser user\"."
          },
          "device": {
            "type": [
              "string",
              "null"
            ],
            "description": "Device name, `Web browser (portal)` for browser sessions, or `vendor access`."
          },
          "app": {
            "type": [
              "string",
              "null"
            ],
            "description": "Name of the app (connection) or private network being used."
          },
          "recording": {
            "type": "boolean",
            "description": "Whether this app records sessions."
          },
          "path": {
            "type": [
              "string",
              "null"
            ],
            "description": "The Cloudraw edge nodes the session crosses, joined with \" → \"."
          },
          "edge": {
            "type": [
              "string",
              "null"
            ],
            "description": "The Cloudraw edge node the session entered through."
          },
          "lat_ms": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Latency in ms, when known."
          },
          "started_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the session started."
          },
          "kind": {
            "type": "string",
            "enum": [
              "device",
              "browser"
            ],
            "description": "Live sessions only: `device` = Cloudraw Connect or vendor access; `browser` = clientless browser access through the portal."
          },
          "connection_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Live sessions only: the app (connection) used."
          },
          "private_network_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Live sessions only: the private network used."
          },
          "device_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Live sessions only: the device."
          },
          "person_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Live sessions only: the person who owns the device or signed in to the portal."
          },
          "jit_grant_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Live sessions only: the just-in-time vendor grant, for vendor access."
          },
          "routers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Live sessions only: the edge nodes on the path, in order."
          },
          "browser": {
            "type": "object",
            "properties": {
              "launch_id": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The portal launch that opened this session."
              },
              "ip": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The browser's public IP address."
              },
              "via": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "How it was launched (for example `admin-test` for a console test)."
              },
              "recording_id": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The recording of this session, if recorded."
              }
            },
            "description": "Browser sessions only."
          }
        },
        "required": [
          "id",
          "source",
          "state"
        ]
      },
      "LiveSessionList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LiveSession"
            }
          },
          "counts_by_app": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            },
            "description": "Active sessions per app name, over the whole workspace (filters do not apply)."
          },
          "overlay": {
            "type": "string",
            "enum": [
              "ok",
              "unavailable"
            ],
            "description": "`unavailable` = live sessions could not be read right now; the list then holds only portal-reported sessions. It never silently comes back empty."
          },
          "next_page": {
            "type": "null",
            "description": "Always null: the list is not paginated."
          }
        },
        "required": [
          "items",
          "overlay"
        ]
      },
      "AccessHistoryEntry": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Session id (`ovl_…`)."
          },
          "live": {
            "type": "boolean",
            "description": "true = still open."
          },
          "kind": {
            "type": "string",
            "enum": [
              "device",
              "browser",
              "other"
            ],
            "description": "`device` = Cloudraw Connect or vendor access, `browser` = portal browser access, `other` = reported by a connector for a client Cloudraw could not match to a device."
          },
          "device_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "device_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "person_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "user": {
            "type": [
              "string",
              "null"
            ],
            "description": "Person display name or e-mail."
          },
          "app": {
            "type": [
              "string",
              "null"
            ],
            "description": "App (connection) or private network name."
          },
          "connection_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "private_network_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "target": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "description": "App type (`rdp`, `ssh`, `http`, …)."
                  },
                  "host": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "port": {
                    "type": [
                      "integer",
                      "null"
                    ]
                  }
                },
                "required": [
                  "type"
                ]
              },
              {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "private_network"
                    ]
                  },
                  "cidrs": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "translated_cidr": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "required": [
                  "type"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "What the app or private network points at."
          },
          "via": {
            "type": "string",
            "enum": [
              "cloudraw connect",
              "browser",
              "vendor access"
            ],
            "description": "How the person connected."
          },
          "ip": {
            "type": [
              "string",
              "null"
            ],
            "description": "Public IP address, for browser sessions."
          },
          "edge": {
            "type": [
              "string",
              "null"
            ],
            "description": "The Cloudraw edge node the session entered through."
          },
          "path": {
            "type": [
              "string",
              "null"
            ],
            "description": "The Cloudraw edge nodes the session crossed."
          },
          "started_at": {
            "type": "string",
            "format": "date-time"
          },
          "ended_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "null while open."
          },
          "duration_s": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Seconds; null while open."
          },
          "dst": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "proto": {
                    "type": "string",
                    "description": "`tcp` or `udp`."
                  },
                  "ip": {
                    "type": "string"
                  },
                  "port": {
                    "type": "integer"
                  }
                },
                "required": [
                  "ip",
                  "port"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "The exact destination inside your network, when the connector reported it."
          },
          "bytes_in": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Bytes received, as reported by the connector."
          },
          "bytes_out": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Bytes sent, as reported by the connector."
          },
          "end_reason": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why the connector saw the session end."
          },
          "reported_by": {
            "type": [
              "string",
              "null"
            ],
            "description": "The connector that reported destination and byte counts."
          },
          "probe": {
            "type": "boolean",
            "description": "Only with `include_probes=true`: true = an automatic Cloudraw Connect reachability check (not a session; never in `by_app`)."
          },
          "probe_anomaly": {
            "type": "boolean",
            "description": "This device + app had more than one check-like connection per 2-minute beat (not the cadence of Cloudraw Connect): worth a look."
          }
        },
        "required": [
          "id",
          "live",
          "started_at"
        ]
      },
      "AccessHistory": {
        "type": "object",
        "properties": {
          "days": {
            "type": "integer",
            "description": "The window actually used (1-30)."
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AccessHistoryEntry"
            },
            "description": "Newest first."
          },
          "by_app": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "app": {
                  "type": "string",
                  "description": "App name, or `(unknown)`."
                },
                "sessions": {
                  "type": "integer"
                },
                "total_s": {
                  "type": "integer",
                  "description": "Sum of session durations in seconds."
                }
              }
            },
            "description": "Totals per app over the returned window (before `limit`), most sessions first."
          },
          "probes_excluded": {
            "type": "integer",
            "description": "Automatic reachability checks by Cloudraw Connect that were left out (they are not sessions); 0 with `include_probes=true`."
          },
          "probes_included": {
            "type": "integer",
            "description": "Only with `include_probes=true`: how many listed entries are reachability checks (`probe: true`)."
          },
          "retention_days": {
            "type": "integer",
            "description": "How long history is kept (30)."
          },
          "note": {
            "type": "string",
            "description": "Known limits of the history."
          }
        },
        "required": [
          "days",
          "items"
        ]
      },
      "AuditEntry": {
        "type": "object",
        "additionalProperties": true,
        "description": "One audit log entry. Every change in the workspace — in the console, through the API, by an integrator, by Cloudraw support or automatically — writes one.\n\nThe common fields are listed below. Each `action` adds its own fields that name what was touched (for example `person`, `device`, `connection`, `connector`, `private_network`, `rule`, `grant`, `session`, `token`, `reason`, `note`, `count`); `?target=` searches those id fields.\n\nEntries are never edited after they are written. `hash` chains each entry to the one before it (see `GET …/audit/verify`).",
        "properties": {
          "at": {
            "type": "string",
            "format": "date-time",
            "description": "When it happened (UTC)."
          },
          "tseq": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Your workspace's own sequence number: 1, 2, 3 … with no gaps. A gap in what you stored means you missed entries."
          },
          "action": {
            "type": "string",
            "description": "What happened, dotted: `<object>.<verb>` (for example `person.invite`, `device.quarantine`, `session.kill`, `audit.export`). `?action=` matches a prefix, so `device.` returns every device action."
          },
          "tenant": {
            "type": "string",
            "description": "Your workspace id."
          },
          "actor": {
            "type": "string",
            "description": "Who did it: an admin e-mail; `token:<token name>` for an API token; `Integrator <name> (<member>)`; `Cloudraw support (<name>) for case <id>`; `Cloudraw staff (<name>)`; `Cloudraw (automatic)`; or `system` for scheduled work."
          },
          "actor_kind": {
            "type": "string",
            "enum": [
              "partner",
              "cloudraw_support",
              "cloudraw_staff",
              "automation"
            ],
            "description": "Set when the actor is not one of your own admins or tokens."
          },
          "actor_role": {
            "type": "string",
            "description": "Admin role of the actor at the time (`owner`, `security_admin`, `connector_op`, `auditor`, `helpdesk`; an API token shows its role ceiling)."
          },
          "via": {
            "type": "string",
            "description": "Channel: `panel` (the Cloudraw console), `api` (an API token; entries written before 13 Oct 2026 show `panel`), `scim` (SCIM provisioning), `self-service`, `device`, `operator` (Cloudraw staff), or a feature-specific value such as `sso` or `connector`."
          },
          "ip": {
            "type": "string",
            "description": "Source IP address of the caller (the admin's browser for console actions)."
          },
          "via_ip": {
            "type": "string",
            "description": "The hop the request came through, when it differs from `ip`."
          },
          "req_id": {
            "type": "string",
            "description": "Request id; quote it to Cloudraw support."
          },
          "partner_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "The integrator, when `actor_kind` is `partner`."
          },
          "support_grant": {
            "type": [
              "string",
              "null"
            ],
            "description": "The support access grant, when `actor_kind` is `cloudraw_support`."
          },
          "support_case": {
            "type": [
              "string",
              "null"
            ],
            "description": "The support case the grant belongs to."
          },
          "break_glass": {
            "type": "boolean",
            "description": "Emergency support access."
          },
          "support_suggestion": {
            "type": "string",
            "description": "Set when an owner applied a change suggested by Cloudraw support."
          },
          "hash": {
            "type": "string",
            "description": "Hash chaining this entry to the previous one (hex)."
          },
          "alg": {
            "type": "string",
            "enum": [
              "hmac"
            ],
            "description": "Keyed hash; absent on older entries (plain SHA-256)."
          }
        },
        "required": [
          "at",
          "action"
        ]
      },
      "AuditPage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AuditEntry"
            },
            "description": "Newest first."
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Opaque cursor for the next (older) page; null on the last page."
          },
          "next_page": {
            "type": "null",
            "description": "Always null; kept for older clients. Use `next_cursor`."
          }
        },
        "required": [
          "items",
          "next_cursor"
        ]
      },
      "AuditVerification": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "true = every entry of the audit chain verified, yours included; false = an unexplained break was found (Cloudraw operations is alerted)."
          },
          "tenant_entries": {
            "type": "integer",
            "description": "How many audit entries your workspace has."
          },
          "tenant_seq_head": {
            "type": "integer",
            "description": "The highest `tseq` in your workspace. With gap-free numbering this equals `tenant_entries`; compare it with the entries you have stored."
          },
          "verified_at": {
            "type": "string",
            "format": "date-time"
          },
          "detail": {
            "type": "string",
            "description": "One-sentence verdict."
          }
        },
        "required": [
          "ok",
          "tenant_entries",
          "verified_at",
          "detail"
        ]
      },
      "AlertTriage": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "new",
              "acknowledged",
              "resolved",
              "dismissed"
            ],
            "description": "`new` → `acknowledged` → `resolved` | `dismissed`; resolved and dismissed alerts can be reopened (back to `new`)."
          },
          "assignee": {
            "type": [
              "string",
              "null"
            ],
            "description": "Who owns the alert (set on acknowledge)."
          },
          "acknowledged_by": {
            "type": [
              "string",
              "null"
            ]
          },
          "acknowledged_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "resolution": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "kind": {
                "type": "string",
                "enum": [
                  "resolved",
                  "dismissed"
                ]
              },
              "reason": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Dismiss reason: `false_positive`, `expected_activity`, `benign`, `duplicate`, `accepted_risk`, or `suppressed` (auto-dismissed by a suppression rule). Null when resolved."
              },
              "note": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "by": {
                "type": "string"
              },
              "at": {
                "type": "string",
                "format": "date-time"
              }
            },
            "description": "How the alert was closed; null while it is open."
          },
          "suppressed_by": {
            "type": [
              "string",
              "null"
            ],
            "description": "Id of the suppression rule that auto-dismissed this alert, if any."
          },
          "history": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "at": {
                  "type": "string",
                  "format": "date-time"
                },
                "by": {
                  "type": "string",
                  "description": "Who made the change."
                },
                "action": {
                  "type": "string",
                  "enum": [
                    "acknowledge",
                    "resolve",
                    "dismiss",
                    "reopen"
                  ]
                },
                "from": {
                  "type": "string",
                  "enum": [
                    "new",
                    "acknowledged",
                    "resolved",
                    "dismissed"
                  ]
                },
                "to": {
                  "type": "string",
                  "enum": [
                    "new",
                    "acknowledged",
                    "resolved",
                    "dismissed"
                  ]
                },
                "reason": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Dismiss reason (`suppressed` when a suppression rule dismissed it)."
                },
                "note": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              }
            },
            "description": "The last 20 triage steps, oldest first."
          }
        },
        "required": [
          "status"
        ],
        "description": "Triage state. Alerts are never deleted: they are acknowledged, resolved or dismissed, and every step is kept here, written to the audit log and streamed to your SIEM."
      },
      "Notification": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "severity": {
            "type": "string",
            "enum": [
              "info",
              "warn",
              "bad"
            ],
            "description": "`bad` = high severity."
          },
          "category": {
            "type": "string",
            "description": "Usually one of `security`, `connector_health`, `device`, `access`, `billing`, `system`, `app_firewall`, `files`; a few events carry a more specific category (for example `trust`, `identity`, `support`)."
          },
          "action": {
            "type": [
              "string",
              "null"
            ],
            "description": "Machine-readable event name, for example `jit_request.create`, `platform_alert.firing`, `security_event`. Null on older alerts."
          },
          "data": {
            "type": [
              "object",
              "null"
            ],
            "description": "Event-specific ids (for example `{ \"grant\": \"…\" }`, `{ \"event\": \"sev_…\" }`).",
            "additionalProperties": true
          },
          "message": {
            "type": "string",
            "description": "Human-readable text, up to 400 characters."
          },
          "view": {
            "type": [
              "string",
              "null"
            ],
            "description": "Console page the alert links to (for example `soc`, `connectors`, `jit`)."
          },
          "param": {
            "type": [
              "string",
              "null"
            ],
            "description": "Optional parameter for that page."
          },
          "read": {
            "type": "boolean",
            "description": "Marked read in the console inbox. Acknowledging, resolving or dismissing also marks it read."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "triage": {
            "$ref": "#/components/schemas/AlertTriage"
          },
          "resolved": {
            "type": "boolean",
            "description": "True only for a sign-up request that was since approved or declined (the alert describes a state that is over)."
          },
          "resolved_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "resolution": {
            "type": "string",
            "enum": [
              "approved",
              "declined"
            ],
            "description": "Only on resolved sign-up requests."
          }
        },
        "required": [
          "id",
          "severity",
          "category",
          "message",
          "read",
          "created_at",
          "triage"
        ]
      },
      "NotificationList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Notification"
            }
          },
          "unread": {
            "type": "integer",
            "description": "Unread alerts in the whole workspace (not only this page)."
          },
          "next_page": {
            "type": "null",
            "description": "Always null: the list is bounded by `limit` (at most 500, newest first)."
          }
        },
        "required": [
          "items",
          "unread"
        ]
      },
      "SecurityEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "at": {
            "type": "string",
            "format": "date-time"
          },
          "category": {
            "type": "string",
            "description": "`blocked` (denied access attempt, the default), `files` (a file transfer that was blocked, held or quarantined) or another short category, up to 40 characters."
          },
          "severity": {
            "type": "string",
            "enum": [
              "info",
              "warn",
              "bad"
            ]
          },
          "actor": {
            "type": [
              "string",
              "null"
            ],
            "description": "The person (e-mail or name) behind the attempt."
          },
          "device": {
            "type": [
              "string",
              "null"
            ],
            "description": "Device name."
          },
          "target_app": {
            "type": [
              "string",
              "null"
            ],
            "description": "Application or resource that was targeted."
          },
          "reason": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why it was blocked, up to 300 characters."
          },
          "file": {
            "type": "object",
            "properties": {
              "path": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "sha256": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "quarantine_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "op": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "`read` or `write`."
              },
              "verdict": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "`blocked`, `held`, `quarantined`, `error` …"
              },
              "code": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "fix": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Suggested fix."
              }
            },
            "description": "Only on `files` events."
          },
          "triage": {
            "$ref": "#/components/schemas/AlertTriage"
          }
        },
        "required": [
          "id",
          "at",
          "category",
          "severity",
          "triage"
        ]
      },
      "SecurityEventList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SecurityEvent"
            }
          },
          "counts": {
            "type": "object",
            "properties": {
              "today": {
                "type": "integer",
                "description": "Events since midnight (server time)."
              },
              "today_blocked": {
                "type": "integer",
                "description": "`blocked` events since midnight."
              },
              "open": {
                "type": "integer",
                "description": "Events that are `new` or `acknowledged`."
              },
              "new": {
                "type": "integer",
                "description": "Events not yet triaged."
              }
            },
            "description": "Workspace-wide counters, independent of the filters."
          },
          "next_page": {
            "type": "null",
            "description": "Always null: the list is bounded by `limit` (at most 500, newest first). The workspace keeps the newest 2000 security events."
          }
        },
        "required": [
          "items",
          "counts"
        ]
      },
      "AlertTriageResult": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "notification",
              "security_event"
            ]
          },
          "severity": {
            "type": "string",
            "enum": [
              "info",
              "warn",
              "bad"
            ]
          },
          "triage": {
            "$ref": "#/components/schemas/AlertTriage"
          }
        },
        "required": [
          "id",
          "kind",
          "triage"
        ]
      },
      "AlertBulkTriageResult": {
        "type": "object",
        "properties": {
          "action": {
            "type": "string",
            "enum": [
              "acknowledge",
              "resolve",
              "dismiss",
              "reopen"
            ]
          },
          "done": {
            "type": "integer",
            "description": "Alerts that changed state."
          },
          "skipped": {
            "type": "integer",
            "description": "Alerts left as they were (see `results[].error`)."
          },
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "kind": {
                  "type": "string",
                  "enum": [
                    "notification",
                    "security_event"
                  ]
                },
                "id": {
                  "type": "string"
                },
                "ok": {
                  "type": "boolean"
                },
                "error": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Why this alert was skipped, for example \"this alert is resolved; acknowledge works from new\"."
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "new",
                    "acknowledged",
                    "resolved",
                    "dismissed"
                  ],
                  "description": "The alert's status after the call."
                }
              }
            }
          }
        },
        "required": [
          "action",
          "done",
          "skipped",
          "results"
        ]
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "description": "Receiver URL (https). Not editable: delete and re-create to change it."
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "security",
                "connector",
                "device",
                "access",
                "jit",
                "all"
              ]
            },
            "description": "Subscribed categories."
          },
          "active": {
            "type": "boolean",
            "description": "False while paused; paused webhooks receive nothing."
          },
          "has_secret": {
            "type": "boolean",
            "description": "A signing secret exists. The secret itself is never returned after creation or rotation."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "last_delivery": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "at": {
                "type": "string",
                "format": "date-time"
              },
              "ok": {
                "type": "boolean"
              },
              "code": {
                "type": "integer",
                "description": "HTTP status of a test delivery (0 when unknown or for queued deliveries)."
              },
              "error": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "test": {
                "type": "boolean",
                "description": "Present and true when this was a test event."
              }
            },
            "description": "Outcome of the most recent delivery attempt; null before the first one."
          }
        },
        "required": [
          "id",
          "url",
          "events",
          "active",
          "has_secret",
          "created_at"
        ]
      },
      "WebhookWithSecret": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Webhook"
          },
          {
            "type": "object",
            "properties": {
              "secret": {
                "type": "string",
                "description": "Signing secret (`whsec_…`). **Shown once** — store it now; it cannot be read back. Rotate it to get a new one."
              }
            },
            "required": [
              "secret"
            ]
          }
        ]
      },
      "WebhookList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Webhook"
            }
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The categories a webhook can subscribe to."
          },
          "next_page": {
            "type": "null",
            "description": "Always null: all webhooks are returned."
          }
        },
        "required": [
          "items",
          "events"
        ]
      },
      "WebhookDelivery": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Event id (`evt_…`). Stable across retries of the same event: use it to drop duplicates."
          },
          "tenant": {
            "type": "string",
            "description": "Your workspace id."
          },
          "category": {
            "type": "string",
            "description": "The event's category: `security`, `connector`, `device`, `access`, `system`, `files`, `app_firewall` or `support`. JIT access events arrive as `access` (their `event.action` starts with `jit_`)."
          },
          "at": {
            "type": "string",
            "format": "date-time",
            "description": "When the event was queued (stable across retries)."
          },
          "event": {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "description": "Event name, for example `security_event`, `platform_alert.firing`, `jit_grant.approve`, `webhook.test`, or `notification.<category>`."
              },
              "severity": {
                "type": "string",
                "description": "`info`, `warn` or `bad` (a few events send `warning`)."
              },
              "message": {
                "type": "string",
                "description": "Human-readable text."
              },
              "data": {
                "type": [
                  "object",
                  "null"
                ],
                "description": "Event-specific ids.",
                "additionalProperties": true
              }
            },
            "required": [
              "action",
              "severity",
              "message"
            ]
          }
        },
        "required": [
          "id",
          "tenant",
          "category",
          "at",
          "event"
        ],
        "description": "The JSON body Cloudraw POSTs to your webhook URL (`Content-Type: application/json`, `User-Agent: cloudraw-notify/1`).\n\n**Signature headers** (sent when the webhook has a signing secret — every webhook created through the API has one):\n- `X-Cloudraw-Signature: sha256=<hex>` — HMAC-SHA256 of the raw body with your signing secret (v0, kept for older receivers).\n- `X-Cloudraw-Timestamp: <unix seconds>` — time of this delivery attempt.\n- `X-Cloudraw-Signature-V1: sha256=<hex>` — HMAC-SHA256 of `<timestamp>.<raw body>` with your signing secret. Verify this one, and reject the request when the timestamp is more than 300 seconds from your clock.\n\nCompute the HMAC over the exact bytes you received (before parsing JSON) and compare in constant time.\n\n**Delivery:** answer with any 2xx within about 8 seconds (15 seconds total). Anything else is retried after 5 s, 30 s, 2 min, 10 min and 30 min (6 attempts in all), then dropped. Retries reuse `id` and `at` but carry a fresh timestamp and signatures. Events are delivered in order per webhook. Alerts dismissed by a suppression rule are not sent.\n\n**Subscriptions** (`events` on the webhook): `security`, `connector`, `device`, `access`, `jit`, `all`. `connector` = connector health; `device` = device trust changes; `jit` = just-in-time access requests and grants; `all` = every event, including `system`, `files`, `app_firewall` and `support` events, which have no category of their own. `audit` and `billing` are not available yet: a subscription to them is refused (`400 category-not-available-yet`); stream the audit log to a SIEM instead (Log streaming). Webhooks created before 13 Oct 2026 with those categories keep working for their other categories; the two are left out of `events` in every answer.",
        "example": {
          "id": "evt_6k2m9x0s8d1q",
          "tenant": "tq7x2m9k4ab",
          "category": "security",
          "at": "2026-10-13T09:24:11.000Z",
          "event": {
            "action": "security_event",
            "severity": "bad",
            "message": "Blocked: Port scan from unmanaged device",
            "data": {
              "event": "sev_9x2k0m8s1d"
            }
          }
        }
      },
      "SiemDestination": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "splunk",
              "sentinel",
              "datadog",
              "s3",
              "syslog",
              "http"
            ]
          },
          "config": {
            "type": "object",
            "additionalProperties": true,
            "description": "The destination settings as saved. Secret fields (`hec_token`, `key`, `client_secret`, `access_key`, `secret_key`, `token` …) are always returned as `••••••••`."
          },
          "streams": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "audit",
                "alerts"
              ]
            },
            "description": "`audit` = the audit log; `alerts` = alerts and their triage changes."
          },
          "status": {
            "type": "string",
            "enum": [
              "configured",
              "streaming",
              "error"
            ],
            "description": "`configured` until the first delivery; `streaming` after a success; `error` after a failure."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "last_event": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Last successful delivery."
          },
          "guide": {
            "type": [
              "object",
              "null"
            ],
            "description": "Setup guide for this destination type (`id`, `section`, `title`, `url`, `pdf_url`)."
          },
          "delivery": {
            "type": [
              "object",
              "null"
            ],
            "description": "Alerts stream queue: `queued`, `delivered`, `dropped`, `failing`, `attempt`, `next_retry_at`, `last_ok_at`, `last_error` (or, after a test only, `{at, ok, error}`). Null before anything was queued."
          },
          "audit_shipping": {
            "type": [
              "object",
              "null"
            ],
            "description": "Audit stream progress: `cursor` and, once shipping ran, `failing`, `failing_since`, `next_retry_at`, `last_ok_at`, `last_error`. Null when the destination does not take the `audit` stream."
          }
        },
        "required": [
          "id",
          "type",
          "config",
          "streams",
          "status",
          "created_at"
        ]
      },
      "SiemDestinationList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SiemDestination"
            }
          },
          "types": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "splunk",
                "sentinel",
                "datadog",
                "s3",
                "syslog",
                "http"
              ]
            },
            "description": "Supported destination types."
          },
          "type_guides": {
            "type": "object",
            "additionalProperties": true,
            "description": "Setup guide per type (null when none)."
          },
          "guide": {
            "type": [
              "object",
              "null"
            ],
            "description": "The general log-streaming guide."
          },
          "streams": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "audit",
                "alerts"
              ]
            }
          },
          "next_page": {
            "type": "null",
            "description": "Always null (at most 10 destinations)."
          }
        },
        "required": [
          "items",
          "types",
          "streams"
        ]
      },
      "SupportCase": {
        "type": "object",
        "properties": {
          "case_id": {
            "type": "string",
            "description": "Case number, `SC-` followed by 6 characters."
          },
          "code": {
            "type": [
              "string",
              "null"
            ],
            "description": "The support code shown on the device or connector when the diagnostics were sent."
          },
          "product": {
            "type": "string",
            "enum": [
              "connect",
              "connector-app",
              "connector-setup",
              "android"
            ],
            "description": "What sent the diagnostics."
          },
          "client_version": {
            "type": [
              "string",
              "null"
            ],
            "description": "Version of the app that sent the first report."
          },
          "os": {
            "type": [
              "string",
              "null"
            ],
            "description": "Operating system reported by the app."
          },
          "diagnosis": {
            "type": "object",
            "properties": {
              "code": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Machine-readable diagnosis code from the app."
              },
              "cause": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Plain-English cause, when the app found one."
              }
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "in_progress",
              "waiting_customer",
              "waiting_cloudraw",
              "resolved",
              "closed"
            ]
          },
          "status_label": {
            "type": "string",
            "description": "`status` as shown in the console (e.g. \"Waiting for you\")."
          },
          "attribution": {
            "type": "string",
            "enum": [
              "cert",
              "claim_ref",
              "hint",
              "anonymous"
            ],
            "description": "How the case was tied to your workspace: `cert` = sent by an enrolled device or connector; `claim_ref` = sent during setup with a one-time setup code of your workspace; `hint` / `anonymous` = sent without a sign-in and attached by an admin."
          },
          "attached_via": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "code_claim",
              "hint_confirm",
              null
            ],
            "description": "For a report attached by an admin: by entering its support code (`code_claim`) or by confirming \"is this yours?\" (`hint_confirm`); otherwise null."
          },
          "device": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "name": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "kind": {
                    "type": "string",
                    "enum": [
                      "device",
                      "connector"
                    ]
                  }
                },
                "required": [
                  "id",
                  "kind"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "The device or connector that sent the diagnostics, when known."
          },
          "counters": {
            "type": "object",
            "properties": {
              "reports": {
                "type": "integer",
                "description": "Diagnostics reports received for this case (including ones no longer listed in `reports`)."
              }
            }
          },
          "reports": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "code": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Support code of this report."
                },
                "received_at": {
                  "type": "string",
                  "format": "date-time"
                },
                "client_version": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              }
            },
            "description": "Reports on this case (the most recent 100). Only summaries: the full log is never available through the API."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "last_seen": {
            "type": "string",
            "format": "date-time",
            "description": "When the latest report arrived."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last change of any kind (new report, status change, reply)."
          },
          "status_changed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "staff_access": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "at": {
                  "type": "string",
                  "format": "date-time"
                },
                "reason": {
                  "type": "string",
                  "description": "Why Cloudraw staff opened the full log."
                },
                "text": {
                  "type": "string",
                  "description": "Ready-made sentence for display."
                }
              }
            },
            "description": "Every time Cloudraw staff opened the full log of this case."
          },
          "messages": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "at": {
                  "type": "string",
                  "format": "date-time"
                },
                "by": {
                  "type": "string",
                  "enum": [
                    "support",
                    "customer"
                  ]
                },
                "author": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Display name: \"Cloudraw support\" or the admin who replied."
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "reply",
                    "known_issue"
                  ],
                  "description": "`known_issue` = an automatic note when the case matches a known problem."
                },
                "text": {
                  "type": "string"
                }
              }
            },
            "description": "The conversation both sides see, oldest first (the most recent 200)."
          },
          "known_issue": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "title": {
                    "type": "string"
                  },
                  "note": {
                    "type": "string",
                    "description": "What to do about it."
                  }
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "Set when the case matches a known problem."
          },
          "can_reply": {
            "type": "boolean",
            "description": "False once the case is closed. Replies are sent from the Cloudraw console."
          },
          "response_time": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "The response-time promise, verbatim (at most 200 characters)."
                  }
                },
                "required": [
                  "text"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "The response time Cloudraw support commits to, or null when none is published."
          }
        },
        "required": [
          "case_id",
          "status",
          "attribution",
          "created_at",
          "updated_at"
        ]
      },
      "SupportCaseList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SupportCase"
            }
          },
          "has_more": {
            "type": "boolean",
            "description": "More cases exist beyond this page."
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "In polling mode: pass it back as `cursor` for the next page. Always null in the default (display) mode."
          },
          "total": {
            "type": "integer",
            "description": "Cases matching `status` / `updated_since`, before paging."
          },
          "generated_at": {
            "type": "string",
            "format": "date-time"
          },
          "response_time": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "The response-time promise, verbatim (at most 200 characters)."
                  }
                },
                "required": [
                  "text"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "The response time Cloudraw support commits to, or null when none is published."
          }
        },
        "required": [
          "items",
          "has_more",
          "next_cursor",
          "total",
          "generated_at"
        ]
      },
      "ProtectionStatusItem": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "enum": [
              "second_step",
              "device_trust",
              "access_rules",
              "app_firewall",
              "recording",
              "browser_controls",
              "file_protection",
              "web_filtering",
              "remembered_sign_in"
            ]
          },
          "configured": {
            "type": "boolean",
            "description": "The protection is switched on / configured somewhere in the workspace."
          },
          "enforcement": {
            "type": "string",
            "enum": [
              "enforced",
              "partial",
              "not_enforced",
              "not_available"
            ],
            "description": "`not_available` = your plan or this service does not provide it."
          },
          "scope": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "local_accounts_only",
              "workspace_sign_in_only",
              "app_access_only",
              "some_rules_not_at_edge",
              "report_only_apps",
              "client_min_version",
              "browser_sessions_only",
              "protected_servers_only",
              null
            ],
            "description": "Only when `enforcement` is `partial`: where the protection IS applied. Otherwise null."
          },
          "coverage": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "enforced": {
                    "type": "integer"
                  },
                  "total": {
                    "type": "integer"
                  }
                },
                "required": [
                  "enforced",
                  "total"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "How many of the things it is configured on (rules, apps, devices, file servers) are really covered; null for workspace-wide protections."
          }
        },
        "required": [
          "key",
          "configured",
          "enforcement",
          "scope",
          "coverage"
        ]
      },
      "ProtectionStatus": {
        "type": "object",
        "properties": {
          "checked_at": {
            "type": "string",
            "format": "date-time"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProtectionStatusItem"
            },
            "description": "One item per protection, in a fixed order. An item whose state cannot be read right now is left out."
          }
        },
        "required": [
          "checked_at",
          "items"
        ]
      },
      "CustomerReportSummary": {
        "type": "object",
        "properties": {
          "month": {
            "type": "string",
            "description": "`YYYY-MM` of the report."
          },
          "label": {
            "type": "string",
            "description": "Month name and year, e.g. \"September 2026\"."
          },
          "stats": {
            "type": "object",
            "properties": {
              "people": {
                "type": "integer",
                "description": "People in the workspace."
              },
              "devices": {
                "type": "integer",
                "description": "Enrolled devices that have connected at least once."
              },
              "sessions": {
                "type": "integer",
                "description": "Access sessions started in the month."
              },
              "incidents": {
                "type": "integer",
                "description": "Alerts opened in the month."
              },
              "changes": {
                "type": "integer",
                "description": "Kinds of configuration change made in the month."
              }
            },
            "required": [
              "people",
              "devices",
              "sessions",
              "incidents",
              "changes"
            ]
          }
        },
        "required": [
          "month",
          "label",
          "stats"
        ]
      },
      "KpiCatalog": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "enum": [
                    "live_sessions",
                    "blocked_today",
                    "open_investigations",
                    "devices_online",
                    "devices_trusted",
                    "apps",
                    "connectors_online",
                    "devices_compliant",
                    "devices_attention",
                    "connect_outdated",
                    "devices_not_seen_7d",
                    "active_users_month",
                    "mfa_coverage",
                    "access_requests_waiting",
                    "seats_used"
                  ]
                },
                "area": {
                  "type": "string",
                  "enum": [
                    "access",
                    "security",
                    "devices",
                    "infrastructure",
                    "licences"
                  ]
                },
                "unit": {
                  "type": "string",
                  "enum": [
                    "count",
                    "percent",
                    "ratio"
                  ],
                  "description": "`ratio` = `value` out of `counts.total`."
                },
                "module": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Paid module the tile needs, or null."
                },
                "trend": {
                  "type": "boolean",
                  "description": "Whether the tile keeps a daily trend."
                },
                "simple_ok": {
                  "type": "boolean"
                },
                "map": {
                  "type": "boolean",
                  "description": "One of the Map page's numbers (the default layout)."
                }
              },
              "required": [
                "id",
                "area",
                "unit"
              ]
            },
            "description": "The tiles YOUR role may use."
          },
          "presets": {
            "type": "object",
            "properties": {},
            "description": "Starting layouts by name (`map`, `owner`, `security`, `it`), limited to what your role may use."
          },
          "default_preset": {
            "type": "string",
            "description": "The layout everyone starts from: `map`."
          },
          "states": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "ok",
                "warn",
                "bad",
                "not_available",
                "building",
                "fewer_than_5"
              ]
            }
          },
          "limits": {
            "type": "object",
            "properties": {
              "ids": {
                "type": "integer",
                "description": "Tiles per values call."
              },
              "layout": {
                "type": "integer",
                "description": "Tiles per layout."
              },
              "ranges": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "cache_s": {
                "type": "integer",
                "description": "Values are cached this long."
              },
              "k_min": {
                "type": "integer",
                "description": "A share over fewer people is not shown."
              }
            }
          }
        },
        "required": [
          "items"
        ]
      },
      "KpiValues": {
        "type": "object",
        "properties": {
          "range": {
            "type": "string",
            "enum": [
              "7d",
              "30d"
            ]
          },
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "enum": [
                    "live_sessions",
                    "blocked_today",
                    "open_investigations",
                    "devices_online",
                    "devices_trusted",
                    "apps",
                    "connectors_online",
                    "devices_compliant",
                    "devices_attention",
                    "connect_outdated",
                    "devices_not_seen_7d",
                    "active_users_month",
                    "mfa_coverage",
                    "access_requests_waiting",
                    "seats_used"
                  ]
                },
                "value": {
                  "type": [
                    "number",
                    "null"
                  ]
                },
                "unit": {
                  "type": "string",
                  "enum": [
                    "count",
                    "percent",
                    "ratio"
                  ]
                },
                "state": {
                  "type": "string",
                  "enum": [
                    "ok",
                    "warn",
                    "bad",
                    "not_available",
                    "building",
                    "fewer_than_5"
                  ]
                },
                "reason": {
                  "type": "string",
                  "description": "Why a tile is `not_available` or `building`, e.g. `no_devices`, `not_checked_yet`, `overlay_unavailable`."
                },
                "counts": {
                  "type": "object",
                  "properties": {},
                  "description": "Small counts that explain the value (e.g. `total` for a ratio, `unknown` for second-step coverage)."
                },
                "trend": {
                  "type": [
                    "object",
                    "null"
                  ],
                  "description": "`{ step: \"1d\", points: [{ t: \"YYYY-MM-DD\", v }] }`, oldest first; null for tiles without a trend."
                },
                "error": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "description": "Set instead of `value` when this one tile could not be computed; the other tiles are unaffected."
                },
                "as_of": {
                  "type": "string",
                  "description": "When the value was computed (values are cached for up to 5 minutes)."
                }
              },
              "required": [
                "id"
              ]
            }
          },
          "dropped": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Requested tiles that are not available to your role."
          }
        },
        "required": [
          "range",
          "items"
        ]
      }
    }
  }
}
