{
    "openapi": "3.1.0",
    "info": {
        "title": "Iroom",
        "version": "1",
        "description": "Create and manage Google Meet rooms, their members, and the files and reports produced by their conferences.\nUse the endpoints below to read or change resources, and webhooks to receive updates in your own service.\n\n**Persian integration guide:** [\u0631\u0627\u0647\u0646\u0645\u0627\u06cc \u0641\u0627\u0631\u0633\u06cc \u0627\u062a\u0635\u0627\u0644 \u0628\u0647 API \u2014 \u062c\u0631\u06cc\u0627\u0646 \u06a9\u0627\u0631\u060c \u0639\u0636\u0648\u06cc\u062a \u0648 \u0647\u0645\u06af\u0627\u0645\u200c\u0633\u0627\u0632\u06cc](https:\/\/iroom.live\/docs\/developer-api\/guide). Includes sequence diagrams, Google account requirements, reusable rooms, and webhook processing.\n\n## Get an API key\n\n1. Sign in to your iRoom account and open [Account settings \u2192 API](https:\/\/iroom.live\/user\/settings?tab=api) (**\u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u2192 API**).\n2. Under **\u06a9\u0644\u06cc\u062f\u0647\u0627\u06cc API**, enter a recognizable name such as `Meeting integration`, then click **\u0627\u06cc\u062c\u0627\u062f \u06a9\u0644\u06cc\u062f** (Create key).\n3. Copy the complete key from the confirmation dialog. It is shown only once; later the dashboard shows only its last four characters.\n4. Store it in your server's environment or secret store. Send the complete value, including the numeric prefix and `|`, in the `Authorization` header.\n\nKeys created here have the `developer-api` ability. You can have up to 30 active keys and revoke a key from the same page. If you lose a key, create a replacement and revoke the old one. Keep keys out of browser code, source control, and URLs.\n\n```http\nAuthorization: Bearer 123|YOUR_API_KEY\nAccept: application\/json\n```\n\nIn this reference's authentication control, enter the full token value; the bearer security scheme supplies the `Bearer` prefix.\nAn absent or invalid token returns `401`; a revoked token or a token without the required ability returns `403`.\n\n### Find your licence key\n\nAn **API key** authenticates your account. A **licence key** identifies the purchased API subscription used by a room. One API key can access the licences belonging to its account; a licence key is not an authentication credential.\n\nStart by listing your licences:\n\n```bash\ncurl 'https:\/\/iroom.live\/api\/v1\/licences' \\\n  -H 'Authorization: Bearer 123|YOUR_API_KEY' \\\n  -H 'Accept: application\/json'\n```\n\nUse a licence's `data[].id` (for example, `lic_0123456789abcdef`) in the `{licence}` path parameter. Check `is_usable` before using licence-scoped endpoints. Creating an API key does not purchase or activate a licence. If the list is empty, purchase an API licence in the dashboard.\n\n## Set up a webhook\n\n1. Open [Account settings \u2192 Webhooks](https:\/\/iroom.live\/user\/settings?tab=webhooks) (**\u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u2192 \u0648\u0628\u200c\u0647\u0648\u06a9\u200c\u0647\u0627**) and select **\u0627\u0641\u0632\u0648\u062f\u0646 \u0648\u0628\u200c\u0647\u0648\u06a9** (Add webhook).\n2. Enter a name and your receiver's URL. The receiver must accept `POST` requests with a JSON body and be reachable from the public internet over HTTPS on port 443. Private\/local addresses, URL user-info credentials, fragments (`#...`), and redirects are not supported.\n3. Choose **all licences** or select one or more API licences belonging to your account. All licences includes future purchases automatically.\n4. Choose **all events** or select one or more event types. All events includes event types added in the future automatically.\n5. Save the endpoint as active to receive matching new events. You can have up to five active endpoints per account. You can also save it as inactive, test it, and activate it later.\n\nWebhook configuration is managed in the dashboard. The reference below documents resource API calls; it does not expose webhook-management endpoints.\nNew endpoints receive future matching updates; they do not automatically receive past events. Webhooks are sent after iRoom discovers a change, so they do not remove Google synchronization delays. There is currently no separate room-created or conference-ended event.\n\n### Authenticate your receiver\n\nYou can include a dedicated, unpredictable receiver token in the URL path or query and validate it in your service:\n\n```text\nhttps:\/\/your-service.example\/webhooks\/iroom?token=YOUR_RECEIVER_TOKEN\n```\n\nUse a token created specifically for your receiver. **Do not put your iRoom API key in this URL.**\niRoom sends to the configured URL without replacing your path or query parameters. It does not generate a signing key or send a signature header. HTTPS protects the connection; your service must validate the receiver token before accepting the body. Event IDs and timestamps are metadata, not authentication.\n\nURLs, including embedded tokens, are stored in endpoint and delivery records and are visible in your account's delivery history. Avoid copying them into public logs or analytics.\n\n### Send a test event\n\nExpand **\u0622\u0632\u0645\u0627\u06cc\u0634 \u0627\u062a\u0635\u0627\u0644** (Test connection) on the endpoint card, choose an event type, and click **\u0627\u0631\u0633\u0627\u0644 \u0631\u0648\u06cc\u062f\u0627\u062f \u0622\u0632\u0645\u0627\u06cc\u0634\u06cc** (Send test event).\nThe event enters the delivery queue and its details open in a modal. Use **\u062a\u0627\u0632\u0647\u200c\u0633\u0627\u0632\u06cc** (Refresh) to see the result, HTTP status, request body, and individual attempts.\n\nTest events use `is_test: true`, `licence_key: \"sandbox_licence\"`, and mock UUIDs. They do not change real meetings or members, and their resource IDs cannot be fetched through the API. Skip real resource fetching for these events. A test targets only the chosen endpoint and ignores its licence\/event filters. Inactive endpoints can be tested; automatically disabled endpoints must be reactivated first.\n\n## Receive and process events\n\nWebhook payloads are **incoming POST request bodies sent by iRoom to your service**, not responses from an iRoom API endpoint.\nEvery event uses this envelope:\n\n| Field | Meaning |\n| --- | --- |\n| `id` | Unique event UUID. Use this as your receiver's idempotency key. |\n| `type` | Event type from the catalogue below. |\n| `version` | Envelope version; currently `1`. |\n| `occurred_at` | Time iRoom recorded the change, as an ISO 8601 UTC timestamp. |\n| `is_test` | `true` for a dashboard test; `false` for a real resource change. |\n| `data` | Minimal resource identifiers and change information. Live events always include `licence_key` and `room_id`. |\n\nThe same event ID and exact body are reused across endpoints, automatic retries, and manual retries. Duplicate deliveries are possible and order is not guaranteed. Maintain durable deduplication by event ID for at least the three-month resend window. If separate receivers share a database but process independently, scope deduplication to the receiver as well as the event ID.\n\n### Request headers\n\n| Header | Value \/ purpose |\n| --- | --- |\n| `Content-Type` | `application\/json` |\n| `Accept` | `application\/json` |\n| `User-Agent` | `iRoom-Webhooks\/1.0` |\n| `Idempotency-Key` | Same UUID as the body's `id`. |\n| `X-iRoom-Event-Id` | Same event UUID. |\n| `X-iRoom-Delivery-Id` | Delivery reference for troubleshooting; do not use it instead of the event ID for deduplication. |\n| `X-iRoom-Timestamp` | Unix timestamp in seconds for this attempt; changes on a retry. |\n\n### Receiver workflow and response\n\n1. Validate your receiver token and parse the JSON body. Reject malformed requests with `400` and invalid tokens with `401`.\n2. Check the event ID. If it has already been durably accepted, acknowledge the duplicate with a successful response.\n3. Persist the new event in your inbox and enqueue its processing durably before acknowledging it.\n4. Return a `2xx` status promptly. The sender has a 15-second total timeout; do not wait for API reads or report processing in your HTTP handler.\n5. In your worker, inspect `type` and fetch the latest resource using `data` identifiers and your **API bearer key**. A test event needs no resource fetch.\n\nA successful receiver response can be empty:\n\n```http\nHTTP\/1.1 204 No Content\n```\n\nOr return `200` with your own optional response body:\n\n```http\nHTTP\/1.1 200 OK\nContent-Type: application\/json\n\n{\"received\": true}\n```\n\nThe status code determines success; iRoom does not require a particular response body. Only a limited response excerpt is retained in delivery history. If you selected all events, tolerate unknown future event types: safely acknowledge and ignore those your service does not yet handle. Do not treat notification order as resource version order; always read the latest API state.\n\n## Webhook event catalogue\n\nAll IDs below are illustrative. Room, conference, member, and artifact IDs are iRoom-owned UUIDs.\nEvents contain identifiers needed to read an update, not full reports, participant emails, file contents, or API credentials.\n\n| Event | When sent | Resource to refresh |\n| --- | --- | --- |\n| `artifact.available` | A file is created in an available state or becomes available. | The artifact endpoint. |\n| `artifact.updated` | File metadata\/status changes, including expiry or removal. | The artifact endpoint or room artifact list. |\n| `report.updated` | A complete attendance report is persisted or audit-log data changes. | Conference attendance or audit-events endpoint, according to `report_type`. |\n| `room.member.updated` | A member\/admin is created, updated, or deleted; includes role and status changes. | The member endpoint or room member list. |\n\n### artifact.available \u2014 file ready\n\n```json\n{\n  \"id\": \"10cd5411-dd1d-416f-a1ad-83702784e41c\",\n  \"type\": \"artifact.available\",\n  \"version\": 1,\n  \"occurred_at\": \"2026-09-08T09:00:00+00:00\",\n  \"is_test\": false,\n  \"data\": {\n    \"licence_key\": \"lic_0123456789abcdef\",\n    \"room_id\": \"7031f075-4f99-43d1-85d4-8bbb8d26df48\",\n    \"conference_id\": \"f9c9e28a-cf51-4600-a5c1-b0b91465c1e0\",\n    \"artifact_id\": \"783c209b-dc75-45b2-a0e7-6d404c162b0f\",\n    \"artifact_type\": \"recording\",\n    \"status\": \"available\"\n  }\n}\n```\n\nFetch `GET \/api\/v1\/licences\/{licence_key}\/rooms\/{room_id}\/artifacts\/{artifact_id}`.\n`conference_id` can be `null` if the file has not been linked to a conference. `artifact_type` can be `recording`, `transcript`, `smart_notes`, `attendance_report`, or `other`.\n\n### artifact.updated \u2014 file changed\n\n```json\n{\n  \"id\": \"d3b67443-0605-4456-9a4d-219972172ac8\",\n  \"type\": \"artifact.updated\",\n  \"version\": 1,\n  \"occurred_at\": \"2026-09-08T10:00:00+00:00\",\n  \"is_test\": false,\n  \"data\": {\n    \"licence_key\": \"lic_0123456789abcdef\",\n    \"room_id\": \"7031f075-4f99-43d1-85d4-8bbb8d26df48\",\n    \"conference_id\": \"f9c9e28a-cf51-4600-a5c1-b0b91465c1e0\",\n    \"artifact_id\": \"783c209b-dc75-45b2-a0e7-6d404c162b0f\",\n    \"artifact_type\": \"recording\",\n    \"status\": \"removed\"\n  }\n}\n```\n\nThe fields are the same as `artifact.available`; `status` can be `pending`, `available`, `expired`, or `removed`.\nRefresh the artifact or `GET \/api\/v1\/licences\/{licence_key}\/rooms\/{room_id}\/artifacts`.\nA removed resource can return `404`; handle that as removal rather than retrying indefinitely. A webhook does not extend file retention or licence validity.\n\n### report.updated \u2014 attendance or audit report changed\n\n```json\n{\n  \"id\": \"d8e8e646-4caa-408b-8783-eef01eb7a93e\",\n  \"type\": \"report.updated\",\n  \"version\": 1,\n  \"occurred_at\": \"2026-09-08T11:00:00+00:00\",\n  \"is_test\": false,\n  \"data\": {\n    \"licence_key\": \"lic_0123456789abcdef\",\n    \"room_id\": \"7031f075-4f99-43d1-85d4-8bbb8d26df48\",\n    \"conference_id\": \"f9c9e28a-cf51-4600-a5c1-b0b91465c1e0\",\n    \"report_type\": \"attendance\"\n  }\n}\n```\n\nFor `report_type: \"attendance\"`, fetch `GET \/api\/v1\/licences\/{licence_key}\/rooms\/{room_id}\/conferences\/{conference_id}\/attendance`.\nFor `report_type: \"audit_log\"`, the same event shape uses that value; fetch `GET \/api\/v1\/licences\/{licence_key}\/rooms\/{room_id}\/conferences\/{conference_id}\/audit-events`.\nThe event does not contain report rows. Follow API pagination to read the report.\n\n### room.member.updated \u2014 member or administrator changed\n\n```json\n{\n  \"id\": \"a5f4d5ef-38be-4b66-979e-941519735ccb\",\n  \"type\": \"room.member.updated\",\n  \"version\": 1,\n  \"occurred_at\": \"2026-09-08T12:00:00+00:00\",\n  \"is_test\": false,\n  \"data\": {\n    \"licence_key\": \"lic_0123456789abcdef\",\n    \"room_id\": \"7031f075-4f99-43d1-85d4-8bbb8d26df48\",\n    \"member_id\": \"91aeb597-8e5f-492f-b91b-b8f8d2e6a501\",\n    \"action\": \"updated\",\n    \"role\": \"admin\",\n    \"status\": \"active\"\n  }\n}\n```\n\n`action` is `created`, `updated`, or `deleted`. `role` is `guest` or `admin`. `status` is `pending`, `active`, `failed`, or `removed`.\nA removed member may be represented by an `updated` event with `status: \"removed\"`; physical deletion uses `action: \"deleted\"` and `status: \"removed\"`.\nFetch `GET \/api\/v1\/licences\/{licence_key}\/rooms\/{room_id}\/members\/{member_id}` or refresh the room's `\/members` list. A physically deleted member can return `404`.\n\n### Example: fetch the resource after a webhook\n\nAfter receiving the `artifact.available` example, your background worker can make this authenticated request:\n\n```bash\ncurl 'https:\/\/iroom.live\/api\/v1\/licences\/lic_0123456789abcdef\/rooms\/7031f075-4f99-43d1-85d4-8bbb8d26df48\/artifacts\/783c209b-dc75-45b2-a0e7-6d404c162b0f' \\\n  -H 'Authorization: Bearer 123|YOUR_API_KEY' \\\n  -H 'Accept: application\/json'\n```\n\nUse the values from the real event, not the example UUIDs. Resource response schemas and examples are documented under the corresponding endpoints below.\n\n## Delivery retries and history\n\n- A `2xx` response completes delivery. Network failures and HTTP `408`, `429`, `500`, `502`, `503`, and `504` are retried automatically.\n- There are at most **10 attempts per delivery cycle, including the first request**. Delays after consecutive failures are 60, 120, 240, 480, 960, 1920, 3840, 7680, and 15360 seconds. Queue load can delay an attempt further.\n- Other statuses, including `3xx`, `400`, `401`, `403`, and `404`, stop automatic retries. Redirects are never followed.\n- Open **\u0633\u0648\u0627\u0628\u0642 \u0627\u0631\u0633\u0627\u0644** (Delivery history) on an endpoint, then **\u0645\u0634\u0627\u0647\u062f\u0647\u0654 \u062c\u0632\u0626\u06cc\u0627\u062a** (Details) to inspect the body, status, timestamps, HTTP results, duration, and response excerpts. Logs and events are retained for **three calendar months**.\n- After fixing a failed or cancelled delivery, use **\u0627\u0631\u0633\u0627\u0644 \u0645\u062c\u062f\u062f** (Retry delivery). The endpoint must be active. This starts a new cycle with the same event ID and body, preserving previous attempt history.\n- More than **1,000 failed attempts within 30 minutes** automatically disables the endpoint. An in-app notification is recorded and email\/SMS notifications are queued through the account's available contact channels. Fix your receiver and reactivate the endpoint manually.\n- Deactivation stops future live delivery; a request already in flight may finish. Changing the URL cancels queued deliveries to the old URL. Manual retries use the current URL. Changing filters affects future events; it does not rewrite deliveries already created.\n\n## API request conventions\n\n### Identifiers and idempotency\n\nSpaces, members, and artifacts are addressed by iRoom-owned UUIDs.\nRoom creation requires a UUID `Idempotency-Key` header generated by your client. Reuse it only when retrying the same create request. This is separate from the event ID generated by iRoom for an outgoing webhook.\n\n### Request correlation\n\nEvery API response carries `X-Request-ID` and `X-API-Version: 1`. Send your own UUID in `X-Request-ID` to correlate a call with your logs; it is echoed in the response and in error bodies.\n\n### Errors\n\nEvery API failure uses this shape:\n\n```json\n{\n  \"error\": {\n    \"code\": \"room_not_found\",\n    \"message\": \"The room was not found.\",\n    \"request_id\": \"8fc5fc3a-6235-4e71-a8de-b3503ea4561d\"\n  }\n}\n```\n\nValidation failures (`422`, code `validation_failed`) add a `details` object keyed by field name. Branch on stable `code` values rather than message text.\n\n### Pagination\n\nList endpoints accept `per_page` (default 20, maximum 100) and an opaque `cursor`. Responses contain `data`, `links`, and `meta`; pass `meta.next_cursor` as the next request's `cursor`. A `null` next cursor means the last page. Do not construct or parse cursors.\n\n### Google synchronization and member writes\n\nNormal member writes wait for Google's response. Admins that could not be added during room creation can remain `pending` while background retries settle them. Subscribe to `room.member.updated` for later changes and read the member's latest API state. Files and reports appear after background synchronization discovers and stores them; subscribe to their events to avoid repeatedly checking for those updates.\n"
    },
    "servers": [
        {
            "url": "https:\/\/iroom.live\/api\/v1",
            "description": "iroom.live"
        },
        {
            "url": "https:\/\/api.iroom.live\/api\/v1",
            "description": "api.iroom.live"
        }
    ],
    "tags": [
        {
            "name": "Licences"
        },
        {
            "name": "Rooms"
        },
        {
            "name": "Members"
        },
        {
            "name": "Conferences"
        },
        {
            "name": "Attendance"
        },
        {
            "name": "Artifacts"
        },
        {
            "name": "Audit log"
        }
    ],
    "security": [
        {
            "http": []
        }
    ],
    "paths": {
        "\/licences": {
            "get": {
                "operationId": "developer-api.v1.licences.index",
                "description": "Every licence on your account, usable or not, newest first. Start here: the `key` of the\nlicence you want is what the rest of the API's paths are built from.",
                "summary": "List your licences",
                "tags": [
                    "Licences"
                ],
                "responses": {
                    "200": {
                        "description": "`LicenceCollection`",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/LicenceCollection"
                                        }
                                    },
                                    "required": [
                                        "data"
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        },
        "\/licences\/{licence}": {
            "get": {
                "operationId": "developer-api.v1.licences.show",
                "description": "Current billing period, room quota, included-minute usage, member caps, and any overage.\nRead this before creating rooms to know how much headroom this licence has left.",
                "summary": "Retrieve one licence",
                "tags": [
                    "Licences"
                ],
                "parameters": [
                    {
                        "name": "licence",
                        "in": "path",
                        "required": true,
                        "description": "The licence key",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`LicenceResource`",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/LicenceResource"
                                        }
                                    },
                                    "required": [
                                        "data"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#\/components\/responses\/ModelNotFoundException"
                    }
                }
            }
        },
        "\/licences\/{licence}\/rooms": {
            "get": {
                "operationId": "developer-api.v1.rooms.index",
                "description": "Every room created under this licence, newest first. Rooms created under a different\nlicence are not listed here, even though you own both \u2014 a room belongs to the licence that\npays for it.",
                "summary": "List rooms",
                "tags": [
                    "Rooms"
                ],
                "parameters": [
                    {
                        "name": "licence",
                        "in": "path",
                        "required": true,
                        "description": "The licence key",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "description": "Items per page. Defaults to 20, capped at 100.",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 100
                        }
                    },
                    {
                        "name": "cursor",
                        "in": "query",
                        "description": "Opaque cursor taken from `meta.next_cursor` of a previous response.",
                        "schema": {
                            "type": "string",
                            "maxLength": 2000
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`RoomCollection`",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/RoomCollection"
                                        }
                                    },
                                    "required": [
                                        "data"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#\/components\/responses\/ModelNotFoundException"
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    }
                }
            },
            "post": {
                "operationId": "developer-api.v1.rooms.store",
                "description": "Does everything in one request: the Google Meet space is created and every `admins` entry\nis added before you get a response. Nothing is left to settle in the background, so the\nroom you get back is final and immediately usable.\n\nThe room is created under the licence in the path, and its quota, usage and billing all\nbelong to that licence.\n\nAdmins are capped here because Google has no batch member method \u2014 each admin costs one\ncall, and an unbounded list would run past the request timeout. Add anyone else afterwards\nwith `POST \/rooms\/{room}\/members`, one member per call.\n\nIf Google rejects an admin the room is still created and returned, because the space\nalready exists by then and cannot be un-created cleanly. That admin comes back under\n`members` with a `failure` explaining why, and is retried in the background. Read\n`members[].status` to see who actually made it.\n\nRequires an `Idempotency-Key` header holding a UUID \u2014 replaying the same key with the same\npayload returns the original room rather than creating another.",
                "summary": "Create a room",
                "tags": [
                    "Rooms"
                ],
                "parameters": [
                    {
                        "name": "licence",
                        "in": "path",
                        "required": true,
                        "description": "The licence key",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "Idempotency-Key",
                        "in": "header",
                        "required": true,
                        "description": "A UUID that makes this creation replay-safe.",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application\/json": {
                            "schema": {
                                "$ref": "#\/components\/schemas\/StoreRoomRequest"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Idempotent replay of an already-created room.",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/RoomResource"
                                        }
                                    },
                                    "required": [
                                        "data"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#\/components\/responses\/ModelNotFoundException"
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    },
                    "201": {
                        "description": "Room created.",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/RoomResource"
                                        }
                                    },
                                    "required": [
                                        "data"
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        },
        "\/licences\/{licence}\/rooms\/{room}": {
            "get": {
                "operationId": "developer-api.v1.rooms.show",
                "summary": "Retrieve a room",
                "tags": [
                    "Rooms"
                ],
                "parameters": [
                    {
                        "name": "licence",
                        "in": "path",
                        "required": true,
                        "description": "The licence key",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "room",
                        "in": "path",
                        "required": true,
                        "description": "The room ID",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`RoomResource`",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/RoomResource"
                                        }
                                    },
                                    "required": [
                                        "data"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#\/components\/responses\/ModelNotFoundException"
                    }
                }
            },
            "patch": {
                "operationId": "developer-api.v1.rooms.update",
                "description": "Configuration changes are pushed to Google Meet with a field mask; omitted fields are left\nuntouched.",
                "summary": "Update a room",
                "tags": [
                    "Rooms"
                ],
                "parameters": [
                    {
                        "name": "licence",
                        "in": "path",
                        "required": true,
                        "description": "The licence key",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "room",
                        "in": "path",
                        "required": true,
                        "description": "The room ID",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "content": {
                        "application\/json": {
                            "schema": {
                                "$ref": "#\/components\/schemas\/UpdateRoomRequest"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "`RoomResource`",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/RoomResource"
                                        }
                                    },
                                    "required": [
                                        "data"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#\/components\/responses\/ModelNotFoundException"
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    }
                }
            }
        },
        "\/licences\/{licence}\/rooms\/{room}\/end-active-conference": {
            "post": {
                "operationId": "developer-api.v1.rooms.end-active-conference",
                "description": "Ejects all participants from the conference currently running in this room.\n\nThis is idempotent. If the host already ended the meeting from the Google Meet UI there is\nnothing left to end and the call still succeeds, returning `200` instead of `202`. Callers\ndo not need to check whether a conference is running first.\n\nUsage and artifacts are reconciled by a background sync, so the room returned here is not\nyet final; poll `GET \/rooms\/{room}` for the settled state.",
                "summary": "End the active conference",
                "tags": [
                    "Rooms"
                ],
                "parameters": [
                    {
                        "name": "licence",
                        "in": "path",
                        "required": true,
                        "description": "The licence key",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "room",
                        "in": "path",
                        "required": true,
                        "description": "The room ID",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "No conference was active; nothing to end.",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/RoomResource"
                                        }
                                    },
                                    "required": [
                                        "data"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#\/components\/responses\/ModelNotFoundException"
                    },
                    "202": {
                        "description": "The active conference is being torn down.",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/RoomResource"
                                        }
                                    },
                                    "required": [
                                        "data"
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        },
        "\/licences\/{licence}\/rooms\/{room}\/members": {
            "get": {
                "operationId": "developer-api.v1.members.index",
                "summary": "List members",
                "tags": [
                    "Members"
                ],
                "parameters": [
                    {
                        "name": "licence",
                        "in": "path",
                        "required": true,
                        "description": "The licence key",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "room",
                        "in": "path",
                        "required": true,
                        "description": "The room ID",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "description": "Items per page. Defaults to 20, capped at 100.",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 100
                        }
                    },
                    {
                        "name": "cursor",
                        "in": "query",
                        "description": "Opaque cursor taken from `meta.next_cursor` of a previous response.",
                        "schema": {
                            "type": "string",
                            "maxLength": 2000
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`MemberCollection`",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/MemberCollection"
                                        }
                                    },
                                    "required": [
                                        "data"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#\/components\/responses\/ModelNotFoundException"
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    }
                }
            },
            "post": {
                "operationId": "developer-api.v1.members.store",
                "description": "Adds one guest and waits for Google to confirm it, so the returned member is already\n`active`. If Google rejects the address, nothing is stored as active and the error says\nwhy.",
                "summary": "Add a guest",
                "tags": [
                    "Members"
                ],
                "parameters": [
                    {
                        "name": "licence",
                        "in": "path",
                        "required": true,
                        "description": "The licence key",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "room",
                        "in": "path",
                        "required": true,
                        "description": "The room ID",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application\/json": {
                            "schema": {
                                "$ref": "#\/components\/schemas\/AddMemberRequest"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The guest is configured on the room.",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/MemberResource"
                                        }
                                    },
                                    "required": [
                                        "data"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#\/components\/responses\/ModelNotFoundException"
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    }
                }
            }
        },
        "\/licences\/{licence}\/rooms\/{room}\/admins": {
            "post": {
                "operationId": "developer-api.v1.admins.store",
                "description": "Same as adding a guest, but the member is configured as a Google `COHOST` and can manage\nthe meeting.",
                "summary": "Add an admin",
                "tags": [
                    "Members"
                ],
                "parameters": [
                    {
                        "name": "licence",
                        "in": "path",
                        "required": true,
                        "description": "The licence key",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "room",
                        "in": "path",
                        "required": true,
                        "description": "The room ID",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application\/json": {
                            "schema": {
                                "$ref": "#\/components\/schemas\/AddMemberRequest"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The admin is configured on the room.",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/MemberResource"
                                        }
                                    },
                                    "required": [
                                        "data"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#\/components\/responses\/ModelNotFoundException"
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    }
                }
            }
        },
        "\/licences\/{licence}\/rooms\/{room}\/members\/{member}": {
            "get": {
                "operationId": "developer-api.v1.members.show",
                "summary": "Retrieve a member",
                "tags": [
                    "Members"
                ],
                "parameters": [
                    {
                        "name": "licence",
                        "in": "path",
                        "required": true,
                        "description": "The licence key",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "room",
                        "in": "path",
                        "required": true,
                        "description": "The room ID",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "member",
                        "in": "path",
                        "required": true,
                        "description": "The member ID",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`MemberResource`",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/MemberResource"
                                        }
                                    },
                                    "required": [
                                        "data"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#\/components\/responses\/ModelNotFoundException"
                    }
                }
            },
            "patch": {
                "operationId": "developer-api.v1.members.update",
                "description": "Google exposes no member update, so this is carried out as a delete followed by a create.\nBoth happen during the request, and the member returned already holds the new role.",
                "summary": "Change a member's role",
                "tags": [
                    "Members"
                ],
                "parameters": [
                    {
                        "name": "licence",
                        "in": "path",
                        "required": true,
                        "description": "The licence key",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "room",
                        "in": "path",
                        "required": true,
                        "description": "The room ID",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "member",
                        "in": "path",
                        "required": true,
                        "description": "The member ID",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application\/json": {
                            "schema": {
                                "$ref": "#\/components\/schemas\/UpdateMemberRequest"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "`MemberResource`",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/MemberResource"
                                        }
                                    },
                                    "required": [
                                        "data"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#\/components\/responses\/ModelNotFoundException"
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    }
                }
            },
            "delete": {
                "operationId": "developer-api.v1.members.destroy",
                "description": "The member is removed at Google first; their slot against the room's configured-member\nlimit is only freed once Google confirms it.",
                "summary": "Remove a member",
                "tags": [
                    "Members"
                ],
                "parameters": [
                    {
                        "name": "licence",
                        "in": "path",
                        "required": true,
                        "description": "The licence key",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "room",
                        "in": "path",
                        "required": true,
                        "description": "The room ID",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "member",
                        "in": "path",
                        "required": true,
                        "description": "The member ID",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`MemberResource`",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/MemberResource"
                                        }
                                    },
                                    "required": [
                                        "data"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#\/components\/responses\/ModelNotFoundException"
                    }
                }
            }
        },
        "\/licences\/{licence}\/rooms\/{room}\/conferences": {
            "get": {
                "operationId": "developer-api.v1.conferences.index",
                "description": "Every conference held in this space, newest first, with its duration and billable\nminutes. A space is reusable, so this doubles as the per-space usage ledger.",
                "summary": "List conferences",
                "tags": [
                    "Conferences"
                ],
                "parameters": [
                    {
                        "name": "licence",
                        "in": "path",
                        "required": true,
                        "description": "The licence key",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "room",
                        "in": "path",
                        "required": true,
                        "description": "The room ID",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "description": "Items per page. Defaults to 20, capped at 100.",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 100
                        }
                    },
                    {
                        "name": "cursor",
                        "in": "query",
                        "description": "Opaque cursor taken from `meta.next_cursor` of a previous response.",
                        "schema": {
                            "type": "string",
                            "maxLength": 2000
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`ConferenceCollection`",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/ConferenceCollection"
                                        }
                                    },
                                    "required": [
                                        "data"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#\/components\/responses\/ModelNotFoundException"
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    }
                }
            }
        },
        "\/licences\/{licence}\/rooms\/{room}\/artifacts": {
            "get": {
                "operationId": "developer-api.v1.artifacts.index",
                "description": "Recordings, transcripts, smart notes, and attendance reports discovered for this space's\nconferences, newest first. Entries disappear once their retention deadline passes.",
                "summary": "List artifacts",
                "tags": [
                    "Artifacts"
                ],
                "parameters": [
                    {
                        "name": "licence",
                        "in": "path",
                        "required": true,
                        "description": "The licence key",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "room",
                        "in": "path",
                        "required": true,
                        "description": "The room ID",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "description": "Items per page. Defaults to 20, capped at 100.",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 100
                        }
                    },
                    {
                        "name": "cursor",
                        "in": "query",
                        "description": "Opaque cursor taken from `meta.next_cursor` of a previous response.",
                        "schema": {
                            "type": "string",
                            "maxLength": 2000
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`ArtifactCollection`",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/ArtifactCollection"
                                        }
                                    },
                                    "required": [
                                        "data"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#\/components\/responses\/ModelNotFoundException"
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    }
                }
            }
        },
        "\/licences\/{licence}\/rooms\/{room}\/artifacts\/{artifact}": {
            "get": {
                "operationId": "developer-api.v1.artifacts.show",
                "summary": "Retrieve an artifact",
                "tags": [
                    "Artifacts"
                ],
                "parameters": [
                    {
                        "name": "licence",
                        "in": "path",
                        "required": true,
                        "description": "The licence key",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "room",
                        "in": "path",
                        "required": true,
                        "description": "The room ID",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "artifact",
                        "in": "path",
                        "required": true,
                        "description": "The artifact ID",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`ArtifactResource`",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/ArtifactResource"
                                        }
                                    },
                                    "required": [
                                        "data"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#\/components\/responses\/ModelNotFoundException"
                    }
                }
            },
            "delete": {
                "operationId": "developer-api.v1.artifacts.destroy",
                "description": "Permanently removes access to the artifact and removes it from subsequent artifact lists.\nThe operation cannot be reversed through the Developer API. There is no request body. A\nsuccessful response returns the artifact once with `status=removed`; later attempts return\n`404`.",
                "summary": "Remove an artifact",
                "tags": [
                    "Artifacts"
                ],
                "parameters": [
                    {
                        "name": "licence",
                        "in": "path",
                        "required": true,
                        "description": "The licence key",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "room",
                        "in": "path",
                        "required": true,
                        "description": "The room ID",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "artifact",
                        "in": "path",
                        "required": true,
                        "description": "The artifact ID",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The artifact was removed.",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/ArtifactResource"
                                        }
                                    },
                                    "required": [
                                        "data"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "The licence, room, or artifact does not exist for the authenticated user.",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "message": {
                                            "type": "string",
                                            "description": "Error overview."
                                        }
                                    },
                                    "required": [
                                        "message"
                                    ]
                                }
                            }
                        }
                    },
                    "502": {
                        "description": "The storage provider could not complete removal; the artifact remains active.",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "string"
                                }
                            }
                        }
                    },
                    "503": {
                        "description": "Artifact removal is temporarily unavailable for this licence tier.",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "string"
                                }
                            }
                        }
                    }
                }
            }
        },
        "\/licences\/{licence}\/rooms\/{room}\/artifacts\/{artifact}\/permissions": {
            "get": {
                "operationId": "developer-api.v1.artifacts.permissions.index",
                "description": "Returns every visible Google Drive permission for this artifact. Permission `type` can be\n`user`, `group`, `domain`, or `anyone`. Permission `role` can be `viewer`, `commenter`,\n`editor`, or `owner`. Use `can_manage` to decide whether the permission may be changed or\nremoved, and pass its opaque `id` to the change\/revoke endpoints.\n\n`anyone` represents public-link access and includes `public_url`. `owner` and inherited\npermissions are returned with `can_manage=false`. Internal platform ownership is omitted\nentirely and cannot be discovered through this endpoint.",
                "summary": "List artifact access",
                "tags": [
                    "Artifacts"
                ],
                "parameters": [
                    {
                        "name": "licence",
                        "in": "path",
                        "required": true,
                        "description": "The licence key",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "room",
                        "in": "path",
                        "required": true,
                        "description": "The room ID",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "artifact",
                        "in": "path",
                        "required": true,
                        "description": "The artifact ID",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The visible users, groups, domains, and public-link access for this artifact.",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/ArtifactPermissionCollection"
                                        }
                                    },
                                    "required": [
                                        "data"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#\/components\/responses\/ModelNotFoundException"
                    },
                    "410": {
                        "description": "The artifact is expired, pending, or has no Google Drive file.",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "string"
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "operationId": "developer-api.v1.artifacts.permissions.store",
                "description": "Creates or updates one Google Drive permission. This endpoint is idempotent for the same\ntarget: if that email or public-link permission already exists, its role is updated.\n\nAllowed `type` values:\n- `user`: share with one Google account. `email` is required.\n- `anyone`: enable public-link access. `email` must be omitted.\n\nAllowed `role` values:\n- `viewer`: can open and download the file.\n- `commenter`: can open and comment where the Google file type supports comments.\n- `editor`: can edit the file. This role is only valid with `type=user`.\n\n`notify` defaults to `true` and controls Google's sharing email for `type=user`. It is\nignored for `type=anyone`.\n\nUser example: `{\"type\":\"user\",\"email\":\"person@example.com\",\"role\":\"viewer\",\"notify\":true}`\n\nPublic-link example: `{\"type\":\"anyone\",\"role\":\"viewer\"}`",
                "summary": "Grant artifact access",
                "tags": [
                    "Artifacts"
                ],
                "parameters": [
                    {
                        "name": "licence",
                        "in": "path",
                        "required": true,
                        "description": "The licence key",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "room",
                        "in": "path",
                        "required": true,
                        "description": "The room ID",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "artifact",
                        "in": "path",
                        "required": true,
                        "description": "The artifact ID",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "content": {
                        "application\/json": {
                            "schema": {
                                "allOf": [
                                    {
                                        "$ref": "#\/components\/schemas\/StoreArtifactPermissionRequest"
                                    },
                                    {
                                        "type": "object",
                                        "properties": {
                                            "type": {
                                                "type": "string",
                                                "description": "Permission target. Allowed values: `user`, `anyone`.",
                                                "examples": [
                                                    "user"
                                                ]
                                            },
                                            "email": {
                                                "type": "string",
                                                "format": "email",
                                                "description": "Google account email. Required when `type=user`; forbidden when `type=anyone`.",
                                                "examples": [
                                                    "person@example.com"
                                                ]
                                            },
                                            "role": {
                                                "type": "string",
                                                "description": "Access level. Allowed values: `viewer`, `commenter`, `editor`. `editor` cannot be used with `type=anyone`.",
                                                "examples": [
                                                    "viewer"
                                                ]
                                            },
                                            "notify": {
                                                "type": "boolean",
                                                "description": "Whether Google sends a sharing email for user access. Defaults to `true`.",
                                                "default": true,
                                                "examples": [
                                                    true
                                                ]
                                            }
                                        },
                                        "required": [
                                            "type",
                                            "role"
                                        ]
                                    }
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Artifact access was granted.",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/ArtifactPermissionResource"
                                        }
                                    },
                                    "required": [
                                        "data"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#\/components\/responses\/ModelNotFoundException"
                    },
                    "422": {
                        "description": "The request contains an unsupported type\/role combination or invalid email.",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "message": {
                                            "type": "string",
                                            "description": "Errors overview."
                                        },
                                        "errors": {
                                            "type": "object",
                                            "description": "A detailed description of each field that failed validation.",
                                            "additionalProperties": {
                                                "type": "array",
                                                "items": {
                                                    "type": "string"
                                                }
                                            }
                                        }
                                    },
                                    "required": [
                                        "message",
                                        "errors"
                                    ]
                                }
                            }
                        }
                    },
                    "410": {
                        "description": "The artifact is expired, pending, or has no Google Drive file.",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "string"
                                }
                            }
                        }
                    }
                }
            }
        },
        "\/licences\/{licence}\/rooms\/{room}\/artifacts\/{artifact}\/permissions\/{permission}": {
            "patch": {
                "operationId": "developer-api.v1.artifacts.permissions.update",
                "description": "Changes the role of one permission returned by **List artifact access**. The `permission`\npath value is the opaque permission `id`; it is scoped to this exact licence, room, and\nartifact and cannot be reused for another file.\n\nAllowed `role` values are `viewer`, `commenter`, and `editor`. Public-link permissions\n(`type=anyone`) accept only `viewer` or `commenter`. Permissions where `can_manage=false`\ncannot be changed and are reported as not found.\n\nExample: `{\"role\":\"commenter\"}`",
                "summary": "Change artifact access",
                "tags": [
                    "Artifacts"
                ],
                "parameters": [
                    {
                        "name": "licence",
                        "in": "path",
                        "required": true,
                        "description": "The licence key",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "room",
                        "in": "path",
                        "required": true,
                        "description": "The room ID",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "artifact",
                        "in": "path",
                        "required": true,
                        "description": "The artifact ID",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "permission",
                        "in": "path",
                        "required": true,
                        "description": "Opaque permission ID returned by List artifact access.",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "requestBody": {
                    "content": {
                        "application\/json": {
                            "schema": {
                                "allOf": [
                                    {
                                        "$ref": "#\/components\/schemas\/UpdateArtifactPermissionRequest"
                                    },
                                    {
                                        "type": "object",
                                        "properties": {
                                            "role": {
                                                "type": "string",
                                                "description": "New access level. Allowed values: `viewer`, `commenter`, `editor`.",
                                                "examples": [
                                                    "commenter"
                                                ]
                                            }
                                        },
                                        "required": [
                                            "role"
                                        ]
                                    }
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The permission with its updated role.",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/ArtifactPermissionResource"
                                        }
                                    },
                                    "required": [
                                        "data"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "The permission is absent, protected, inherited, or not manageable.",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "message": {
                                            "type": "string",
                                            "description": "Error overview."
                                        }
                                    },
                                    "required": [
                                        "message"
                                    ]
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "`editor` was requested for public-link access, or the role is invalid.",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "message": {
                                            "type": "string",
                                            "description": "Errors overview."
                                        },
                                        "errors": {
                                            "type": "object",
                                            "description": "A detailed description of each field that failed validation.",
                                            "additionalProperties": {
                                                "type": "array",
                                                "items": {
                                                    "type": "string"
                                                }
                                            }
                                        }
                                    },
                                    "required": [
                                        "message",
                                        "errors"
                                    ]
                                }
                            }
                        }
                    },
                    "410": {
                        "description": "The artifact is expired, pending, or has no Google Drive file.",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "string"
                                }
                            }
                        }
                    }
                }
            },
            "delete": {
                "operationId": "developer-api.v1.artifacts.permissions.destroy",
                "description": "Removes one permission returned by **List artifact access**. Use the opaque permission `id`\nfrom that response. User, group, domain, and public-link permissions may be removed only\nwhen `can_manage=true`.\n\nInherited, owner, and internal platform permissions cannot be removed. Protected and\nunknown IDs deliberately return the same `404` response.",
                "summary": "Revoke artifact access",
                "tags": [
                    "Artifacts"
                ],
                "parameters": [
                    {
                        "name": "licence",
                        "in": "path",
                        "required": true,
                        "description": "The licence key",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "room",
                        "in": "path",
                        "required": true,
                        "description": "The room ID",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "artifact",
                        "in": "path",
                        "required": true,
                        "description": "The artifact ID",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "permission",
                        "in": "path",
                        "required": true,
                        "description": "Opaque permission ID returned by List artifact access.",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "204": {
                        "description": "Artifact access was revoked.",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "array",
                                    "items": {}
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "The permission is absent, protected, inherited, or not manageable.",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "message": {
                                            "type": "string",
                                            "description": "Error overview."
                                        }
                                    },
                                    "required": [
                                        "message"
                                    ]
                                }
                            }
                        }
                    },
                    "410": {
                        "description": "The artifact is expired, pending, or has no Google Drive file.",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "string"
                                }
                            }
                        }
                    }
                }
            }
        },
        "\/licences\/{licence}\/rooms\/{room}\/conferences\/{conference}\/attendance": {
            "get": {
                "operationId": "developer-api.v1.conferences.attendance",
                "description": "Who attended this conference and for how long, longest first, each with the sessions it was\nsummed from. Built from Google's participants and participantSessions: Google publishes no\nattendance report through its API, and discards conference records after roughly 30 days,\nso this is what survives.\n\nAttendance is collected once, on the first sync after the conference ends \u2014 while it is\nstill running, sessions have no end time and any total would be wrong, so this is empty.\n`attendance_synced_at` on the conference tells the two apart.",
                "summary": "List conference attendance",
                "tags": [
                    "Attendance"
                ],
                "parameters": [
                    {
                        "name": "licence",
                        "in": "path",
                        "required": true,
                        "description": "The licence key",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "room",
                        "in": "path",
                        "required": true,
                        "description": "The room ID",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "conference",
                        "in": "path",
                        "required": true,
                        "description": "The conference ID",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "description": "Items per page. Defaults to 20, capped at 100.",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 100
                        }
                    },
                    {
                        "name": "cursor",
                        "in": "query",
                        "description": "Opaque cursor taken from `meta.next_cursor` of a previous response.",
                        "schema": {
                            "type": "string",
                            "maxLength": 2000
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`ParticipantCollection`",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/ParticipantCollection"
                                        }
                                    },
                                    "required": [
                                        "data"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#\/components\/responses\/ModelNotFoundException"
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    }
                }
            }
        },
        "\/licences\/{licence}\/rooms\/{room}\/conferences\/{conference}\/audit-events": {
            "get": {
                "operationId": "developer-api.v1.conferences.audit-events",
                "description": "Everything the Google Workspace admin log recorded for this conference, oldest first: each\njoin and leave, plus recording, presentation, chat, knocking and reaction activity, and the\nnetwork quality every endpoint reported.\n\nThe companion to attendance rather than a replacement for it. Attendance comes from the Meet\nAPI and answers who was present and for how long; this is the raw admin log, which is richer\nbut arrives on Google's own schedule \u2014 it lags the conference by hours, so `data` is empty\nand `report` is null until Google publishes it.",
                "summary": "List conference audit events",
                "tags": [
                    "Audit log"
                ],
                "parameters": [
                    {
                        "name": "licence",
                        "in": "path",
                        "required": true,
                        "description": "The licence key",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "room",
                        "in": "path",
                        "required": true,
                        "description": "The room ID",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "conference",
                        "in": "path",
                        "required": true,
                        "description": "The conference ID",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "description": "Items per page. Defaults to 20, capped at 100.",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 100
                        }
                    },
                    {
                        "name": "cursor",
                        "in": "query",
                        "description": "Opaque cursor taken from `meta.next_cursor` of a previous response.",
                        "schema": {
                            "type": "string",
                            "maxLength": 2000
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`AuditEventCollection`",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#\/components\/schemas\/AuditEventCollection"
                                        },
                                        "report": {
                                            "anyOf": [
                                                {
                                                    "description": "Null until Google has published the log, which lags the conference by hours.",
                                                    "$ref": "#\/components\/schemas\/AuditReportResource"
                                                },
                                                {
                                                    "type": "null"
                                                }
                                            ]
                                        }
                                    },
                                    "required": [
                                        "data",
                                        "report"
                                    ]
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#\/components\/responses\/ModelNotFoundException"
                    },
                    "422": {
                        "$ref": "#\/components\/responses\/ValidationException"
                    }
                }
            }
        }
    },
    "components": {
        "securitySchemes": {
            "http": {
                "type": "http",
                "scheme": "bearer"
            }
        },
        "schemas": {
            "AddMemberRequest": {
                "type": "object",
                "description": "One member per request: Google exposes no batch member method, so a list would just be a loop\nwith a worse failure story \u2014 a caller can loop and decide what to do about each result.\n\nThe role comes from the route, not the body, so there is nothing to send but an address.",
                "properties": {
                    "email": {
                        "type": "string",
                        "format": "email",
                        "description": "Email address of the user to configure on the room.",
                        "maxLength": 255
                    }
                },
                "required": [
                    "email"
                ],
                "title": "AddMemberRequest"
            },
            "ArtifactCollection": {
                "type": "array",
                "items": {
                    "$ref": "#\/components\/schemas\/ArtifactResource"
                },
                "title": "ArtifactCollection"
            },
            "ArtifactPermissionCollection": {
                "type": "array",
                "items": {
                    "$ref": "#\/components\/schemas\/ArtifactPermissionResource"
                },
                "title": "ArtifactPermissionCollection"
            },
            "ArtifactPermissionResource": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string"
                    },
                    "object": {
                        "type": "string",
                        "const": "artifact_permission"
                    },
                    "type": {
                        "type": "string",
                        "description": "One of `user`, `group`, `domain`, or `anyone`."
                    },
                    "email": {
                        "type": "string"
                    },
                    "domain": {
                        "type": "string"
                    },
                    "display_name": {
                        "type": "string"
                    },
                    "photo_url": {
                        "type": "string"
                    },
                    "role": {
                        "type": "string",
                        "description": "One of `viewer`, `commenter`, `editor`, or `owner`."
                    },
                    "inherited": {
                        "type": "string"
                    },
                    "can_manage": {
                        "type": "string"
                    },
                    "public_url": {
                        "type": "string"
                    }
                },
                "required": [
                    "id",
                    "object",
                    "type",
                    "email",
                    "domain",
                    "display_name",
                    "photo_url",
                    "role",
                    "inherited",
                    "can_manage",
                    "public_url"
                ],
                "title": "ArtifactPermissionResource"
            },
            "ArtifactResource": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "object": {
                        "type": "string",
                        "const": "meeting_artifact"
                    },
                    "conference_id": {
                        "type": "string",
                        "description": "Conference that produced this artifact."
                    },
                    "type": {
                        "type": "string",
                        "description": "One of `recording`, `transcript`, `smart_notes`, `attendance_report`, `other`."
                    },
                    "status": {
                        "type": "string",
                        "description": "One of `pending`, `available`, `expired`, `removed`. Reported as `expired` once\n`expires_at` has passed, whatever the stored state."
                    },
                    "name": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "mime_type": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "size_bytes": {
                        "type": "integer"
                    },
                    "view_url": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Google viewer URL. Access still follows the file permissions returned separately."
                    },
                    "download_url": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Authenticated download endpoint, or `null` while unavailable or past retention."
                    },
                    "available_at": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "expires_at": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "synced_at": {
                        "type": [
                            "string",
                            "null"
                        ]
                    }
                },
                "required": [
                    "id",
                    "object",
                    "conference_id",
                    "type",
                    "status",
                    "name",
                    "mime_type",
                    "size_bytes",
                    "view_url",
                    "download_url",
                    "available_at",
                    "expires_at",
                    "synced_at"
                ],
                "title": "ArtifactResource"
            },
            "AuditEventCollection": {
                "type": "array",
                "items": {
                    "$ref": "#\/components\/schemas\/AuditEventResource"
                },
                "title": "AuditEventCollection"
            },
            "AuditEventResource": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string"
                    },
                    "object": {
                        "type": "string",
                        "const": "conference_audit_event"
                    },
                    "event_name": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Google's own name, e.g. `call_ended`, `recording_activity`, `hand_raised`."
                    },
                    "started_at": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "ended_at": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "action_time": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Set instead of a start\/end pair for events that are a moment, not a span."
                    },
                    "duration_seconds": {
                        "anyOf": [
                            {
                                "type": "integer"
                            },
                            {
                                "type": "number"
                            },
                            {
                                "type": "null"
                            }
                        ]
                    },
                    "actor": {
                        "type": "object",
                        "description": "Who the event is about. The log identifies people inconsistently \u2014 a signed-in\nattendee carries an email and profile id, while an external or anonymous one is\nonly ever a display name \u2014 so every shape is passed through as Google gave it.",
                        "properties": {
                            "display_name": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "email": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "profile_id": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "key": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "description": "e.g. `HANGOUTS_EXTERNAL_OR_ANONYMOUS` for an attendee Google cannot name."
                            },
                            "identifier": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "identifier_type": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            }
                        },
                        "required": [
                            "display_name",
                            "email",
                            "profile_id",
                            "key",
                            "identifier",
                            "identifier_type"
                        ]
                    },
                    "device": {
                        "type": "object",
                        "properties": {
                            "type": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "endpoint_id": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            }
                        },
                        "required": [
                            "type",
                            "endpoint_id"
                        ]
                    },
                    "media": {
                        "type": "object",
                        "description": "Seconds of each stream this endpoint sent and received. Only `call_ended` carries these.",
                        "properties": {
                            "audio_send_seconds": {
                                "anyOf": [
                                    {
                                        "type": "integer"
                                    },
                                    {
                                        "type": "number"
                                    },
                                    {
                                        "type": "null"
                                    }
                                ]
                            },
                            "audio_recv_seconds": {
                                "anyOf": [
                                    {
                                        "type": "integer"
                                    },
                                    {
                                        "type": "number"
                                    },
                                    {
                                        "type": "null"
                                    }
                                ]
                            },
                            "video_send_seconds": {
                                "anyOf": [
                                    {
                                        "type": "integer"
                                    },
                                    {
                                        "type": "number"
                                    },
                                    {
                                        "type": "null"
                                    }
                                ]
                            },
                            "video_recv_seconds": {
                                "anyOf": [
                                    {
                                        "type": "integer"
                                    },
                                    {
                                        "type": "number"
                                    },
                                    {
                                        "type": "null"
                                    }
                                ]
                            },
                            "screencast_send_seconds": {
                                "anyOf": [
                                    {
                                        "type": "integer"
                                    },
                                    {
                                        "type": "number"
                                    },
                                    {
                                        "type": "null"
                                    }
                                ]
                            },
                            "screencast_recv_seconds": {
                                "anyOf": [
                                    {
                                        "type": "integer"
                                    },
                                    {
                                        "type": "number"
                                    },
                                    {
                                        "type": "null"
                                    }
                                ]
                            }
                        },
                        "required": [
                            "audio_send_seconds",
                            "audio_recv_seconds",
                            "video_send_seconds",
                            "video_recv_seconds",
                            "screencast_send_seconds",
                            "screencast_recv_seconds"
                        ]
                    },
                    "network": {
                        "type": "object",
                        "description": "What the endpoint measured about its own connection. Useful for explaining a bad call.",
                        "properties": {
                            "transport_protocol": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "congestion": {
                                "anyOf": [
                                    {
                                        "type": "integer"
                                    },
                                    {
                                        "type": "number"
                                    },
                                    {
                                        "type": "null"
                                    }
                                ]
                            },
                            "rtt_msec_mean": {
                                "anyOf": [
                                    {
                                        "type": "integer"
                                    },
                                    {
                                        "type": "number"
                                    },
                                    {
                                        "type": "null"
                                    }
                                ]
                            },
                            "send_jitter_msec_mean": {
                                "anyOf": [
                                    {
                                        "type": "integer"
                                    },
                                    {
                                        "type": "number"
                                    },
                                    {
                                        "type": "null"
                                    }
                                ]
                            },
                            "estimated_upload_kbps_mean": {
                                "anyOf": [
                                    {
                                        "type": "integer"
                                    },
                                    {
                                        "type": "number"
                                    },
                                    {
                                        "type": "null"
                                    }
                                ]
                            },
                            "estimated_download_kbps_mean": {
                                "anyOf": [
                                    {
                                        "type": "integer"
                                    },
                                    {
                                        "type": "number"
                                    },
                                    {
                                        "type": "null"
                                    }
                                ]
                            },
                            "audio_send_bitrate_kbps_mean": {
                                "anyOf": [
                                    {
                                        "type": "integer"
                                    },
                                    {
                                        "type": "number"
                                    },
                                    {
                                        "type": "null"
                                    }
                                ]
                            },
                            "audio_send_packet_loss_max": {
                                "anyOf": [
                                    {
                                        "type": "integer"
                                    },
                                    {
                                        "type": "number"
                                    },
                                    {
                                        "type": "null"
                                    }
                                ]
                            },
                            "audio_send_packet_loss_mean": {
                                "anyOf": [
                                    {
                                        "type": "integer"
                                    },
                                    {
                                        "type": "number"
                                    },
                                    {
                                        "type": "null"
                                    }
                                ]
                            }
                        },
                        "required": [
                            "transport_protocol",
                            "congestion",
                            "rtt_msec_mean",
                            "send_jitter_msec_mean",
                            "estimated_upload_kbps_mean",
                            "estimated_download_kbps_mean",
                            "audio_send_bitrate_kbps_mean",
                            "audio_send_packet_loss_max",
                            "audio_send_packet_loss_mean"
                        ]
                    },
                    "organizer_email": {
                        "type": [
                            "string",
                            "null"
                        ]
                    }
                },
                "required": [
                    "id",
                    "object",
                    "event_name",
                    "started_at",
                    "ended_at",
                    "action_time",
                    "duration_seconds",
                    "actor",
                    "device",
                    "media",
                    "network",
                    "organizer_email"
                ],
                "title": "AuditEventResource"
            },
            "AuditReportResource": {
                "type": "object",
                "properties": {
                    "object": {
                        "type": "string",
                        "const": "conference_audit_report"
                    },
                    "meeting_id": {
                        "type": "string",
                        "description": "Google's conference record id, which is what joins this log to the conference."
                    },
                    "meeting_code": {
                        "type": "string",
                        "description": "The dialable code, e.g. `AADORABQTP`. Reused across a room's conferences."
                    },
                    "meeting_time": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "started_at": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "duration_seconds": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "status": {
                        "type": "string",
                        "description": "`pending` while the conference may still produce events, then `completed`."
                    },
                    "is_ongoing": {
                        "type": "boolean",
                        "description": "True while the conference is still running, in which case the duration is a running total and will grow."
                    },
                    "last_event_at": {
                        "type": [
                            "string",
                            "null"
                        ]
                    }
                },
                "required": [
                    "object",
                    "meeting_id",
                    "meeting_code",
                    "meeting_time",
                    "started_at",
                    "duration_seconds",
                    "status",
                    "is_ongoing",
                    "last_event_at"
                ],
                "title": "AuditReportResource"
            },
            "ConferenceCollection": {
                "type": "array",
                "items": {
                    "$ref": "#\/components\/schemas\/ConferenceResource"
                },
                "title": "ConferenceCollection"
            },
            "ConferenceResource": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string"
                    },
                    "object": {
                        "type": "string",
                        "const": "conference"
                    },
                    "status": {
                        "type": "string",
                        "description": "One of `unknown`, `active`, `completed`."
                    },
                    "started_at": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "ended_at": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "duration_minutes": {
                        "type": "integer"
                    },
                    "billable_minutes": {
                        "type": "integer"
                    },
                    "finalized_at": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "artifacts_expire_at": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "participant_count": {
                        "type": "integer",
                        "description": "Distinct people who attended. Zero until attendance is collected."
                    },
                    "attendance_synced_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "When attendance was collected. Null while the conference is still running."
                    },
                    "google_meeting_id": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Google's conference record id, which is also what the Workspace admin log calls its\nmeeting id. Exposed so a caller can line this conference up against exports taken\nstraight from Google."
                    }
                },
                "required": [
                    "id",
                    "object",
                    "status",
                    "started_at",
                    "ended_at",
                    "duration_minutes",
                    "billable_minutes",
                    "finalized_at",
                    "artifacts_expire_at",
                    "participant_count",
                    "attendance_synced_at",
                    "google_meeting_id"
                ],
                "title": "ConferenceResource"
            },
            "LicenceCollection": {
                "type": "array",
                "items": {
                    "$ref": "#\/components\/schemas\/LicenceResource"
                },
                "title": "LicenceCollection"
            },
            "LicenceResource": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "The licence key. Every other endpoint's path is built from this."
                    },
                    "object": {
                        "type": "string",
                        "const": "developer_licence"
                    },
                    "status": {
                        "type": "string",
                        "description": "One of `pending`, `active`, `past_due`, `cancelled`, `expired`. Only an `active`\nlicence with an open period can create rooms; the others are readable but the\nlicence-scoped endpoints will refuse."
                    },
                    "is_usable": {
                        "type": "boolean",
                        "description": "Whether this licence can currently be used to create and manage rooms."
                    },
                    "plan": {
                        "type": "object",
                        "properties": {
                            "slug": {
                                "type": "string"
                            },
                            "title": {
                                "type": "string"
                            },
                            "tier": {
                                "type": "integer",
                                "description": "Google tier this licence's rooms are created on."
                            }
                        },
                        "required": [
                            "slug",
                            "title",
                            "tier"
                        ]
                    },
                    "period": {
                        "type": "object",
                        "properties": {
                            "starts_at": {
                                "type": "string"
                            },
                            "ends_at": {
                                "type": "string"
                            }
                        },
                        "required": [
                            "starts_at",
                            "ends_at"
                        ]
                    },
                    "quota": {
                        "type": "object",
                        "properties": {
                            "meetings": {
                                "type": "object",
                                "properties": {
                                    "used": {
                                        "type": "integer"
                                    },
                                    "limit": {
                                        "type": "integer"
                                    },
                                    "remaining": {
                                        "type": [
                                            "object",
                                            "null"
                                        ]
                                    }
                                },
                                "required": [
                                    "used",
                                    "limit",
                                    "remaining"
                                ]
                            },
                            "included_minutes": {
                                "type": "object",
                                "properties": {
                                    "used": {
                                        "type": "integer"
                                    },
                                    "limit": {
                                        "type": "integer"
                                    },
                                    "remaining": {
                                        "anyOf": [
                                            {
                                                "type": "string"
                                            },
                                            {
                                                "type": "integer",
                                                "enum": [
                                                    0
                                                ]
                                            }
                                        ]
                                    }
                                },
                                "required": [
                                    "used",
                                    "limit",
                                    "remaining"
                                ]
                            },
                            "member_limits": {
                                "type": "object",
                                "properties": {
                                    "admins": {
                                        "type": "integer"
                                    },
                                    "guests": {
                                        "type": "integer"
                                    },
                                    "total": {
                                        "type": "integer"
                                    }
                                },
                                "required": [
                                    "admins",
                                    "guests",
                                    "total"
                                ]
                            }
                        },
                        "required": [
                            "meetings",
                            "included_minutes",
                            "member_limits"
                        ]
                    },
                    "overage": {
                        "type": "object",
                        "properties": {
                            "minutes": {
                                "type": "integer"
                            },
                            "charged_units": {
                                "type": "integer"
                            },
                            "amount": {
                                "type": "integer"
                            }
                        },
                        "required": [
                            "minutes",
                            "charged_units",
                            "amount"
                        ]
                    }
                },
                "required": [
                    "id",
                    "object",
                    "status",
                    "is_usable",
                    "plan",
                    "period",
                    "quota",
                    "overage"
                ],
                "title": "LicenceResource"
            },
            "MemberCollection": {
                "type": "array",
                "items": {
                    "$ref": "#\/components\/schemas\/MemberResource"
                },
                "title": "MemberCollection"
            },
            "MemberResource": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string"
                    },
                    "object": {
                        "type": "string",
                        "const": "meeting_member"
                    },
                    "email": {
                        "type": "string"
                    },
                    "role": {
                        "type": "string",
                        "description": "`admin` (Google `COHOST`) or `guest`."
                    },
                    "status": {
                        "type": "string",
                        "description": "One of `pending`, `active`, `failed`, `removed`. Writes settle asynchronously."
                    },
                    "failure": {
                        "type": [
                            "object",
                            "null"
                        ],
                        "properties": {
                            "code": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "message": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            }
                        },
                        "required": [
                            "code",
                            "message"
                        ]
                    },
                    "created_at": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "synced_at": {
                        "type": [
                            "string",
                            "null"
                        ]
                    }
                },
                "required": [
                    "id",
                    "object",
                    "email",
                    "role",
                    "status",
                    "failure",
                    "created_at",
                    "synced_at"
                ],
                "title": "MemberResource"
            },
            "ParticipantCollection": {
                "type": "array",
                "items": {
                    "$ref": "#\/components\/schemas\/ParticipantResource"
                },
                "title": "ParticipantCollection"
            },
            "ParticipantResource": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string"
                    },
                    "object": {
                        "type": "string",
                        "const": "conference_participant"
                    },
                    "identity_type": {
                        "type": "string",
                        "description": "One of `signed_in`, `anonymous`, `phone`, `unknown`."
                    },
                    "display_name": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "google_user": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Google's `people\/{id}` for the attendee. Only a signed-in Workspace user carries\none, so it is null for anonymous and phone attendees \u2014 they cannot be recognised\nacross conferences."
                    },
                    "first_joined_at": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "last_left_at": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "attended_seconds": {
                        "type": "integer",
                        "description": "Summed across sessions, so time away is not counted."
                    },
                    "session_count": {
                        "type": "integer"
                    },
                    "sessions": {
                        "type": "array",
                        "items": {
                            "$ref": "#\/components\/schemas\/ParticipantSessionResource"
                        }
                    }
                },
                "required": [
                    "id",
                    "object",
                    "identity_type",
                    "display_name",
                    "google_user",
                    "first_joined_at",
                    "last_left_at",
                    "attended_seconds",
                    "session_count"
                ],
                "title": "ParticipantResource"
            },
            "ParticipantSessionResource": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string"
                    },
                    "object": {
                        "type": "string",
                        "const": "participant_session"
                    },
                    "started_at": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "ended_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Null while the session is still open, which is normal mid-conference."
                    },
                    "duration_seconds": {
                        "type": "integer"
                    }
                },
                "required": [
                    "id",
                    "object",
                    "started_at",
                    "ended_at",
                    "duration_seconds"
                ],
                "title": "ParticipantSessionResource"
            },
            "RoomCollection": {
                "type": "array",
                "items": {
                    "$ref": "#\/components\/schemas\/RoomResource"
                },
                "title": "RoomCollection"
            },
            "RoomResource": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "iRoom-owned room identifier. Google `spaces\/*` names are never exposed."
                    },
                    "object": {
                        "type": "string",
                        "const": "room"
                    },
                    "status": {
                        "type": "string",
                        "description": "Lifecycle state: `ready` (created and usable), `active` (a conference is running),\n`completed`, `cancelled`, `failed`. A room is never returned to a caller before it\nis created, so `reserved` and `provisioning` are internal."
                    },
                    "title": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "client_reference": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Your own correlation identifier, echoed back untouched."
                    },
                    "meeting_code": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "join_url": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "access_type": {
                        "type": "string",
                        "description": "One of `open` or `restricted`."
                    },
                    "configuration": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "members": {
                        "type": "array",
                        "description": "The room's configured members, including any admin Google rejected during\ncreation. Check each `status` and `failure` to see who made it.",
                        "items": {
                            "$ref": "#\/components\/schemas\/MemberResource"
                        }
                    },
                    "member_counts": {
                        "type": "object",
                        "properties": {
                            "admins": {
                                "type": "integer"
                            },
                            "guests": {
                                "type": "integer"
                            },
                            "total": {
                                "type": "integer"
                            }
                        },
                        "required": [
                            "admins",
                            "guests",
                            "total"
                        ]
                    },
                    "usage": {
                        "type": "object",
                        "properties": {
                            "duration_minutes": {
                                "type": "integer"
                            },
                            "billable_minutes": {
                                "type": "integer"
                            }
                        },
                        "required": [
                            "duration_minutes",
                            "billable_minutes"
                        ]
                    },
                    "last_error": {
                        "type": [
                            "object",
                            "null"
                        ],
                        "properties": {
                            "code": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "message": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            }
                        },
                        "required": [
                            "code",
                            "message"
                        ]
                    },
                    "created_at": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "google_synced_at": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "artifacts_synced_at": {
                        "type": [
                            "string",
                            "null"
                        ]
                    }
                },
                "required": [
                    "id",
                    "object",
                    "status",
                    "title",
                    "client_reference",
                    "meeting_code",
                    "join_url",
                    "access_type",
                    "configuration",
                    "member_counts",
                    "usage",
                    "last_error",
                    "created_at",
                    "google_synced_at",
                    "artifacts_synced_at"
                ],
                "title": "RoomResource"
            },
            "StoreArtifactPermissionRequest": {
                "type": "object",
                "properties": {
                    "type": {
                        "type": "string",
                        "enum": [
                            "user",
                            "anyone"
                        ]
                    },
                    "email": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "email",
                        "description": "Google account email. Required for `user`; omitted for `anyone`.",
                        "maxLength": 255
                    },
                    "role": {
                        "type": "string",
                        "enum": [
                            "viewer",
                            "commenter",
                            "editor"
                        ]
                    },
                    "notify": {
                        "type": "boolean",
                        "description": "Send Google's sharing email for `user`. Defaults to `true`."
                    }
                },
                "required": [
                    "type",
                    "role",
                    "notify"
                ],
                "title": "StoreArtifactPermissionRequest"
            },
            "StoreRoomRequest": {
                "type": "object",
                "description": "Everything here is applied during the request. Admins are validated up front so a malformed\naddress is rejected before any Google space exists, rather than after.",
                "properties": {
                    "title": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Human-readable label for the room.",
                        "maxLength": 120
                    },
                    "client_reference": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Your own correlation identifier. Stored and echoed back untouched.",
                        "maxLength": 255
                    },
                    "access_type": {
                        "type": "string",
                        "description": "`open` admits anyone with the link. With `restricted`, invited members enter\ndirectly and everyone else waits for an admin to accept their join request."
                    },
                    "admins": {
                        "type": "array",
                        "description": "Emails to configure as co-hosts, added during this request. At most four; add any\nothers afterwards with `POST \/rooms\/{room}\/members`.",
                        "items": {
                            "type": "string",
                            "format": "email",
                            "maxLength": 255
                        },
                        "maxItems": 4
                    },
                    "artifacts": {
                        "type": "object",
                        "description": "Which artifacts Google should generate automatically for each conference.",
                        "properties": {
                            "recording": {
                                "type": "boolean"
                            },
                            "attendance_report": {
                                "type": "boolean",
                                "description": "'artifacts.transcription' => ['sometimes', 'boolean'],\n'artifacts.smart_notes' => ['sometimes', 'boolean'],"
                            }
                        },
                        "required": [
                            "recording",
                            "attendance_report"
                        ]
                    }
                },
                "required": [
                    "access_type"
                ],
                "title": "StoreRoomRequest"
            },
            "UpdateArtifactPermissionRequest": {
                "type": "object",
                "properties": {
                    "role": {
                        "type": "string",
                        "enum": [
                            "viewer",
                            "commenter",
                            "editor"
                        ]
                    }
                },
                "required": [
                    "role"
                ],
                "title": "UpdateArtifactPermissionRequest"
            },
            "UpdateMemberRequest": {
                "type": "object",
                "properties": {
                    "role": {
                        "type": "string"
                    }
                },
                "required": [
                    "role"
                ],
                "title": "UpdateMemberRequest"
            },
            "UpdateRoomRequest": {
                "type": "object",
                "description": "Every field is optional: only what you send is changed, and the Google-side update is sent\nwith a matching field mask.",
                "properties": {
                    "title": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Human-readable label for the room.",
                        "maxLength": 120
                    },
                    "client_reference": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Your own correlation identifier. Stored and echoed back untouched.",
                        "maxLength": 255
                    },
                    "access_type": {
                        "type": "string",
                        "description": "`open` admits anyone with the link. With `restricted`, invited members enter\ndirectly and everyone else waits for an admin to accept their join request."
                    },
                    "artifacts": {
                        "type": "object",
                        "description": "Which artifacts Google should generate automatically for each conference.",
                        "properties": {
                            "recording": {
                                "type": "boolean"
                            },
                            "attendance_report": {
                                "type": "boolean",
                                "description": "'artifacts.transcription' => ['sometimes', 'boolean'],\n'artifacts.smart_notes' => ['sometimes', 'boolean'],"
                            }
                        },
                        "required": [
                            "recording",
                            "attendance_report"
                        ]
                    }
                },
                "title": "UpdateRoomRequest"
            }
        },
        "responses": {
            "ModelNotFoundException": {
                "description": "The requested resource was not found.",
                "content": {
                    "application\/json": {
                        "schema": {
                            "type": "object",
                            "properties": {
                                "error": {
                                    "type": "object",
                                    "properties": {
                                        "code": {
                                            "type": "string",
                                            "description": "Stable machine-readable error code, safe to branch on.",
                                            "examples": [
                                                "resource_not_found"
                                            ]
                                        },
                                        "message": {
                                            "type": "string",
                                            "description": "Human-readable explanation. Do not branch on this."
                                        },
                                        "request_id": {
                                            "type": "string",
                                            "description": "Echoes the `X-Request-ID` response header. Quote this in support requests."
                                        }
                                    },
                                    "required": [
                                        "code",
                                        "message",
                                        "request_id"
                                    ]
                                }
                            },
                            "required": [
                                "error"
                            ]
                        }
                    }
                }
            },
            "ValidationException": {
                "description": "Validation failed. `details` maps each rejected field to its messages.",
                "content": {
                    "application\/json": {
                        "schema": {
                            "type": "object",
                            "properties": {
                                "error": {
                                    "type": "object",
                                    "properties": {
                                        "code": {
                                            "type": "string",
                                            "description": "Stable machine-readable error code, safe to branch on.",
                                            "examples": [
                                                "validation_failed"
                                            ]
                                        },
                                        "message": {
                                            "type": "string",
                                            "description": "Human-readable explanation. Do not branch on this."
                                        },
                                        "request_id": {
                                            "type": "string",
                                            "description": "Echoes the `X-Request-ID` response header. Quote this in support requests."
                                        },
                                        "details": {
                                            "type": "object",
                                            "description": "Per-field validation messages, keyed by field name."
                                        }
                                    },
                                    "required": [
                                        "code",
                                        "message",
                                        "request_id"
                                    ]
                                }
                            },
                            "required": [
                                "error"
                            ]
                        }
                    }
                }
            }
        }
    }
}