openapi: 3.0.3 info: title: Entrosity Matrix Portal API version: 0.1.0 description: > Entrosity Matrix portal REST API: per-tenant control of computer-room internet access through FortiGate firewall policies, via an on-premises connector (rooms on/off, "disable until", address objects of the rooms' address groups, teacher room grants, history). This file is the source of truth for the backend server interfaces (oapi-codegen), request validation, and the frontend types (openapi-typescript). Run `make gen` after editing. Authentication: `Authorization: Bearer `: users sign in on Entrosity Hub, which issues five-minute product tokens for Matrix (`POST /api/platform/v1/auth/product-token {"product":"matrix"}`, with the Hub's session cookie). Users, tenants (the Hub's organizations) and roles are managed on the Hub; Matrix keeps a copy. Every route's access rule (public, authenticated, global admin, tenant permission) is declared in `internal/http/portal/access.go` and enforced before the handler runs. servers: - url: /api/v1 tags: - name: system - name: auth - name: admin - name: tenant - name: connectors - name: firewalls - name: rooms - name: addresses - name: sites - name: grants - name: history - name: events security: - bearerAuth: [] paths: /healthz: get: operationId: getHealthz summary: Liveness probe tags: - system security: [] responses: '200': description: The API process is up. content: application/json: schema: $ref: '#/components/schemas/Health' default: $ref: '#/components/responses/Problem' /auth/sse-token: post: operationId: createStreamToken summary: Short-lived token for a tenant live stream (EventSource) description: | Returns a token valid for 60 seconds that opens `GET /tenants/{tenantID}/stream?sse_token=` for the given tenant and the caller's session. Access to the tenant is checked when the stream opens. Keeps the access token out of URLs. tags: - auth requestBody: required: true content: application/json: schema: type: object additionalProperties: false required: - tenant_id properties: tenant_id: type: string format: uuid responses: '200': description: Stream token. content: application/json: schema: type: object required: - token - expires_in properties: token: type: string expires_in: type: integer description: Seconds. default: $ref: '#/components/responses/Problem' /me: get: operationId: getMe summary: The signed-in user with their tenants and roles tags: - auth responses: '200': description: Current user. content: application/json: schema: $ref: '#/components/schemas/Me' default: $ref: '#/components/responses/Problem' /admin/overview: get: operationId: getAdminOverview summary: Cross-tenant counters tags: - admin responses: '200': description: Overview. content: application/json: schema: $ref: '#/components/schemas/AdminOverview' default: $ref: '#/components/responses/Problem' /admin/connector-releases: get: operationId: listAdminConnectorReleases summary: Stored connector releases, with download links description: >- Every stored Matrix connector installer (the newest ten), newest first, each with a link that needs no sign-in until `download_expires_at`; `current` marks the release connectors are updated to (MATRIX_CONNECTOR_UPDATE_CHANNEL). `adoption` counts the enrolled connectors by version. Empty when releases are off. tags: - admin responses: '200': description: Releases. content: application/json: schema: $ref: '#/components/schemas/AdminConnectorReleaseList' default: $ref: '#/components/responses/Problem' /admin/tenants: get: operationId: listTenants summary: List tenants tags: - admin parameters: - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/PageSize' - $ref: '#/components/parameters/Query' - name: status in: query schema: $ref: '#/components/schemas/TenantStatus' responses: '200': description: Tenants. content: application/json: schema: $ref: '#/components/schemas/TenantList' default: $ref: '#/components/responses/Problem' /admin/users: get: operationId: listGlobalAdmins summary: Global admins (the platform admins of Entrosity Hub) tags: - admin responses: '200': description: Users. content: application/json: schema: $ref: '#/components/schemas/UserDirectory' default: $ref: '#/components/responses/Problem' /admin/audit: get: operationId: listAdminAudit summary: Cross-tenant audit log tags: - admin parameters: - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/PageSize' - name: tenant_id in: query schema: type: string format: uuid - $ref: '#/components/parameters/AuditActor' - $ref: '#/components/parameters/AuditAction' - $ref: '#/components/parameters/AuditResourceType' - $ref: '#/components/parameters/AuditFrom' - $ref: '#/components/parameters/AuditTo' responses: '200': description: Audit entries, newest first. content: application/json: schema: $ref: '#/components/schemas/AuditList' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}: parameters: - $ref: '#/components/parameters/TenantID' get: operationId: getTenant summary: Tenant profile tags: - tenant responses: '200': description: Tenant. content: application/json: schema: $ref: '#/components/schemas/Tenant' default: $ref: '#/components/responses/Problem' patch: operationId: updateTenant summary: Change the tenant's settings (the name is the Hub's) tags: - tenant requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateTenantRequest' responses: '200': description: Updated. content: application/json: schema: $ref: '#/components/schemas/Tenant' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/dashboard: parameters: - $ref: '#/components/parameters/TenantID' get: operationId: getTenantDashboard summary: Counters, firewall health and the last day's changes tags: - tenant responses: '200': description: Dashboard. content: application/json: schema: $ref: '#/components/schemas/TenantDashboard' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/users: parameters: - $ref: '#/components/parameters/TenantID' get: operationId: listTenantUsers summary: Tenant members and their roles (managed on Entrosity Hub) tags: - tenant responses: '200': description: Users. content: application/json: schema: $ref: '#/components/schemas/UserDirectory' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/sites: parameters: - $ref: '#/components/parameters/TenantID' get: operationId: listSites summary: Sites of the tenant tags: - tenant responses: '200': description: Sites. content: application/json: schema: $ref: '#/components/schemas/SiteList' default: $ref: '#/components/responses/Problem' post: operationId: createSite summary: Create a site tags: - tenant requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateSiteRequest' responses: '201': description: Created. content: application/json: schema: $ref: '#/components/schemas/Site' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/sites/{siteID}: parameters: - $ref: '#/components/parameters/TenantID' - $ref: '#/components/parameters/SiteID' get: operationId: getSite summary: Get a site tags: - tenant responses: '200': description: Site. content: application/json: schema: $ref: '#/components/schemas/Site' default: $ref: '#/components/responses/Problem' patch: operationId: updateSite summary: Update a site tags: - tenant requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateSiteRequest' responses: '200': description: Updated. content: application/json: schema: $ref: '#/components/schemas/Site' default: $ref: '#/components/responses/Problem' delete: operationId: deleteSite summary: Delete a site (its connectors and firewalls stay, without a site) tags: - tenant responses: '204': description: Deleted. default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/audit: parameters: - $ref: '#/components/parameters/TenantID' get: operationId: listTenantAudit summary: Audit log of the tenant tags: - tenant parameters: - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/PageSize' - $ref: '#/components/parameters/AuditActor' - $ref: '#/components/parameters/AuditAction' - $ref: '#/components/parameters/AuditResourceType' - $ref: '#/components/parameters/AuditFrom' - $ref: '#/components/parameters/AuditTo' responses: '200': description: Audit entries, newest first. content: application/json: schema: $ref: '#/components/schemas/AuditList' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/stream: parameters: - $ref: '#/components/parameters/TenantID' get: operationId: streamTenantEvents summary: Live updates (server-sent events) description: > `text/event-stream` of the tenant's live updates: `matrix.rooms` (`{firewall_id}`: reload the rooms), `matrix.addresses` (`{firewall_id}`: reload the address groups), `matrix.sites` (`{firewall_id}`: reload the allowed sites), `matrix.change` (a change event finished), `connector.status` and `job.update`. Authenticate with a bearer token or, for EventSource, `?sse_token=` from `POST /auth/sse-token`. Teachers get only the events of the rooms granted to them (`matrix.change`: changes of those rooms; `job.update`: their jobs) and of the firewalls they hold a room on. tags: - events parameters: - name: sse_token in: query schema: type: string maxLength: 4096 responses: '200': description: Event stream. content: text/event-stream: schema: type: string default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/enrollment-tokens: parameters: - $ref: '#/components/parameters/TenantID' get: operationId: listEnrollmentTokens summary: Connector enrollment tokens of the tenant tags: - connectors responses: '200': description: Tokens, newest first. content: application/json: schema: $ref: '#/components/schemas/EnrollmentTokenList' default: $ref: '#/components/responses/Problem' post: operationId: createEnrollmentToken summary: Create a connector enrollment token (the secret is returned once) tags: - connectors requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateEnrollmentTokenRequest' responses: '201': description: Created. `secret` and the commands are shown only now. content: application/json: schema: $ref: '#/components/schemas/CreatedEnrollmentToken' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/enrollment-tokens/{tokenID}: parameters: - $ref: '#/components/parameters/TenantID' - $ref: '#/components/parameters/TokenID' delete: operationId: revokeEnrollmentToken summary: Revoke an enrollment token tags: - connectors responses: '204': description: Revoked. default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/enrollment-tokens/{tokenID}/delete: parameters: - $ref: '#/components/parameters/TenantID' - $ref: '#/components/parameters/TokenID' post: operationId: deleteEnrollmentToken summary: >- Delete an enrollment token permanently (global admins; requires the password) description: | Global admins confirm with their own password: they send `step_up_token`, which Entrosity Hub issues for the password (`POST /api/platform/v1/auth/step-up`, product `matrix`). tags: - connectors requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/DeleteEnrollmentTokenRequest' responses: '204': description: Deleted. default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/connector-release: parameters: - $ref: '#/components/parameters/TenantID' get: operationId: getConnectorRelease summary: The newest connector installer, with a download link description: >- The release connectors are updated to (MATRIX_CONNECTOR_UPDATE_CHANNEL). `download_url` needs no sign-in and works until `download_expires_at`. 404 when no release has been published. tags: - connectors responses: '200': description: The newest release. content: application/json: schema: $ref: '#/components/schemas/ConnectorRelease' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/connectors: parameters: - $ref: '#/components/parameters/TenantID' get: operationId: listConnectors summary: Matrix connectors of the tenant tags: - connectors responses: '200': description: Connectors. content: application/json: schema: $ref: '#/components/schemas/ConnectorList' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/connectors/{connectorID}: parameters: - $ref: '#/components/parameters/TenantID' - $ref: '#/components/parameters/ConnectorID' get: operationId: getConnector summary: Get a connector tags: - connectors responses: '200': description: Connector. content: application/json: schema: $ref: '#/components/schemas/Connector' default: $ref: '#/components/responses/Problem' patch: operationId: updateConnector summary: Rename a connector or move it to a site tags: - connectors requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateConnectorRequest' responses: '200': description: Updated. content: application/json: schema: $ref: '#/components/schemas/Connector' default: $ref: '#/components/responses/Problem' delete: operationId: deleteConnector summary: >- Remove a connector (409 connector_has_firewalls while it serves firewalls) tags: - connectors responses: '204': description: Removed. default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/jobs/{jobID}: parameters: - $ref: '#/components/parameters/TenantID' - $ref: '#/components/parameters/JobID' get: operationId: getJob summary: A connector job (firewall check, refresh, room switch, address change) description: >- 404 for teachers when the job concerns a room (or firewall) not granted to them. tags: - connectors responses: '200': description: Job. content: application/json: schema: $ref: '#/components/schemas/Job' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/firewalls: parameters: - $ref: '#/components/parameters/TenantID' get: operationId: listFirewalls summary: The tenant's firewalls (configuration and last report) tags: - firewalls responses: '200': description: Firewalls. content: application/json: schema: $ref: '#/components/schemas/FirewallList' default: $ref: '#/components/responses/Problem' post: operationId: createFirewall summary: Add a firewall behind one of the tenant's connectors description: | The configuration is sent to the connector (`matrix.firewall.apply`). `writes_enabled` and `address_writes_enabled` default to false. The token is write-only (also `PUT .../token`). 422 with `fields` when the configuration is invalid (e.g. `policy_pattern` without a `(?P…)` group). tags: - firewalls requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateFirewallRequest' responses: '201': description: Added. content: application/json: schema: $ref: '#/components/schemas/Firewall' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/firewalls/{firewallID}: parameters: - $ref: '#/components/parameters/TenantID' - $ref: '#/components/parameters/FirewallID' get: operationId: getFirewall summary: A firewall tags: - firewalls responses: '200': description: Firewall. content: application/json: schema: $ref: '#/components/schemas/Firewall' default: $ref: '#/components/responses/Problem' patch: operationId: updateFirewall summary: Change a firewall (the connector receives the new configuration) description: | Moving the firewall to another connector removes it from the old one. Every change is re-applied (`matrix.firewall.apply`); a disabled firewall is removed from its connector. tags: - firewalls requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateFirewallRequest' responses: '200': description: Updated. content: application/json: schema: $ref: '#/components/schemas/Firewall' default: $ref: '#/components/responses/Problem' delete: operationId: deleteFirewall summary: >- Remove a firewall (the connector forgets it and its token; the history stays) tags: - firewalls responses: '204': description: Removed. default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/firewalls/{firewallID}/token: parameters: - $ref: '#/components/parameters/TenantID' - $ref: '#/components/parameters/FirewallID' put: operationId: setFirewallToken summary: Store the FortiGate REST API token (write-only) description: >- Stored encrypted, never returned; bumps `credentials_version` and re-applies the firewall. tags: - firewalls requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FirewallToken' responses: '204': description: Stored. default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/firewalls/{firewallID}/check: parameters: - $ref: '#/components/parameters/TenantID' - $ref: '#/components/parameters/FirewallID' post: operationId: checkFirewall summary: >- Read-only check of the firewall (version, direction, rooms, groups, warnings) description: | Creates a `matrix.firewall.check` job; its result (`GET /jobs/{jobID}` or `job.update`) is a `CheckResult`. 409 connector_offline. tags: - firewalls responses: '202': description: Check started. content: application/json: schema: $ref: '#/components/schemas/Job' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/firewalls/{firewallID}/refresh: parameters: - $ref: '#/components/parameters/TenantID' - $ref: '#/components/parameters/FirewallID' post: operationId: refreshFirewall summary: Read the firewall now (rooms, address groups or both) tags: - firewalls requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RefreshRequest' responses: '202': description: Refresh started; `matrix.rooms` / `matrix.addresses` follow. content: application/json: schema: $ref: '#/components/schemas/Job' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/rooms: parameters: - $ref: '#/components/parameters/TenantID' get: operationId: listRooms summary: Rooms of every firewall with their state and what the caller may do description: | Teachers see only the rooms granted to them and the firewalls they hold a room on (`firewalls` keeps such a firewall even before its rooms are reported, for its stale and connection state); a teacher without grants gets empty lists. Tenant admins, global admins and viewers see every room. tags: - rooms parameters: - name: firewall_id in: query schema: type: string format: uuid responses: '200': description: Rooms. content: application/json: schema: $ref: '#/components/schemas/RoomsView' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/firewalls/{firewallID}/rooms/{room}/status: parameters: - $ref: '#/components/parameters/TenantID' - $ref: '#/components/parameters/FirewallID' - $ref: '#/components/parameters/RoomCode' post: operationId: setRoomStatus summary: Switch a room's internet access on or off description: | Records the change (`change`) and sends a `matrix.policy.set` job. `reenable_at` (disable only, 5 minutes to 7 days ahead) switches the room on again then; enabling cancels a pending re-enable. Errors: 403 forbidden; 404 unknown_room (for teachers also every room not granted to them, which they do not see); 409 busy, snapshot_stale, connector_offline, writes_disabled, unknown_room (the firewall does not report the room); 429 rate_limited. Refused attempts are recorded too. tags: - rooms requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SetRoomStatusRequest' responses: '202': description: Sent. content: application/json: schema: $ref: '#/components/schemas/RoomStatusChange' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/firewalls/{firewallID}/bulk-status: parameters: - $ref: '#/components/parameters/TenantID' - $ref: '#/components/parameters/FirewallID' post: operationId: setBulkStatus summary: Switch several rooms (a list or a building) at once description: | Teachers must hold a grant for every listed room, otherwise nothing is sent (404 unknown_room: rooms not granted to them do not exist for them); a building means its rooms granted to them. Each room counts against the rate limits. A room with a change already running is skipped (`items[].error` = busy). tags: - rooms requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/BulkStatusRequest' responses: '202': description: Sent. content: application/json: schema: $ref: '#/components/schemas/BulkStatusResult' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/bulk-actions/{bulkID}: parameters: - $ref: '#/components/parameters/TenantID' - $ref: '#/components/parameters/BulkID' get: operationId: getBulkAction summary: A bulk action with the outcome of each room description: 404 for teachers when any of its rooms is not granted to them. tags: - rooms responses: '200': description: Bulk action. content: application/json: schema: $ref: '#/components/schemas/BulkAction' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/schedules: parameters: - $ref: '#/components/parameters/TenantID' get: operationId: listSchedules summary: Re-enable schedules ("disable until") description: Teachers get only the schedules of the rooms granted to them. tags: - rooms parameters: - name: status in: query schema: $ref: '#/components/schemas/ScheduleStatus' responses: '200': description: Schedules, latest re-enable time first. content: application/json: schema: $ref: '#/components/schemas/ScheduleList' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/schedules/{scheduleID}/cancel: parameters: - $ref: '#/components/parameters/TenantID' - $ref: '#/components/parameters/ScheduleID' post: operationId: cancelSchedule summary: Cancel a pending re-enable (the room stays off) description: | 409 schedule_not_pending when it is already firing or finished; 404 unknown_room for a teacher when the room is not granted to them (recorded as refused). tags: - rooms responses: '200': description: Cancelled. content: application/json: schema: $ref: '#/components/schemas/Schedule' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/firewalls/{firewallID}/address-groups: parameters: - $ref: '#/components/parameters/TenantID' - $ref: '#/components/parameters/FirewallID' get: operationId: listAddressGroups summary: Address groups of the firewall's rooms (without members) description: | Teachers get only the groups of the rooms granted to them, and 404 for a firewall they hold no room on. tags: - addresses responses: '200': description: Groups. content: application/json: schema: $ref: '#/components/schemas/AddressGroupsView' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/firewalls/{firewallID}/address-groups/detail: parameters: - $ref: '#/components/parameters/TenantID' - $ref: '#/components/parameters/FirewallID' get: operationId: getAddressGroup summary: >- One address group with its members and the caller's unfinished operations tags: - addresses description: | policy_id and group are required (422 when missing). 404 for a teacher when the group's room is not granted to them. parameters: - name: policy_id in: query schema: type: integer format: int64 minimum: 1 maximum: 4294967295 - name: group in: query schema: type: string minLength: 1 maxLength: 255 responses: '200': description: Group. content: application/json: schema: $ref: '#/components/schemas/AddressGroupDetail' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/firewalls/{firewallID}/addresses/update: parameters: - $ref: '#/components/parameters/TenantID' - $ref: '#/components/parameters/FirewallID' post: operationId: updateAddress summary: Change the IP of a computer's /32 address object description: | Tenant admins only. `request_id` makes the request idempotent (the same request returns the same operation). 409 conflict when the group changed since `group_version`, busy while another address change of the firewall runs. tags: - addresses requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AddressUpdateRequest' responses: '202': description: Sent. content: application/json: schema: $ref: '#/components/schemas/AddressOperationStarted' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/firewalls/{firewallID}/addresses/create: parameters: - $ref: '#/components/parameters/TenantID' - $ref: '#/components/parameters/FirewallID' post: operationId: createAddress summary: Add a computer (/32 address object) to a room's address group tags: - addresses requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AddressCreateRequest' responses: '202': description: Sent. content: application/json: schema: $ref: '#/components/schemas/AddressOperationStarted' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/address-operations/{operationID}: parameters: - $ref: '#/components/parameters/TenantID' - $ref: '#/components/parameters/OperationID' get: operationId: getAddressOperation summary: An address operation and how far it got tags: - addresses responses: '200': description: Operation. content: application/json: schema: $ref: '#/components/schemas/AddressOperation' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/address-operations/{operationID}/retry: parameters: - $ref: '#/components/parameters/TenantID' - $ref: '#/components/parameters/OperationID' post: operationId: retryAddressOperation summary: Resume an interrupted address operation (only its author) description: 409 not_retryable when it never started writing (prepared) or is done. tags: - addresses requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RetryAddressOperationRequest' responses: '202': description: Sent. content: application/json: schema: $ref: '#/components/schemas/AddressOperationStarted' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/firewalls/{firewallID}/allowed-sites: parameters: - $ref: '#/components/parameters/TenantID' - $ref: '#/components/parameters/FirewallID' get: operationId: getAllowedSites summary: Allowed sites of a firewall (shared list and per-room lists) description: | Domains the rooms' computers can still reach while a room's internet is off, as last reported by the connector. `rooms` holds a list for every present room (`exists: false` when its address group is not set up). `can_edit` says whether the caller may change a list (tenant admins: every list; teachers: the lists of rooms granted to them). Readable by everyone who can read rooms; teachers get the shared list (read only) and the lists of the rooms granted to them, and 404 for a firewall they hold no room on. tags: - sites responses: '200': description: Lists. content: application/json: schema: $ref: '#/components/schemas/AllowedSitesView' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/firewalls/{firewallID}/allowed-sites/setup-cli: parameters: - $ref: '#/components/parameters/TenantID' - $ref: '#/components/parameters/FirewallID' get: operationId: getAllowedSitesSetupCLI summary: >- FortiOS CLI that creates the missing allowed-sites groups and policies (tenant admins) description: | Text to paste into the FortiGate CLI: the address groups (member "none") and ACCEPT policies (`edit 0`, the firewall's source → destination, srcaddr = the room address groups) of the shared list and the per-room lists named in `rooms`, only where they are missing. Matrix never creates policies itself. tags: - sites parameters: - name: rooms in: query description: >- Comma-separated room codes whose per-room lists should be set up too. schema: type: string maxLength: 20000 responses: '200': description: CLI. content: application/json: schema: $ref: '#/components/schemas/AllowedSitesSetupCLI' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/firewalls/{firewallID}/allowed-sites/{list}: parameters: - $ref: '#/components/parameters/TenantID' - $ref: '#/components/parameters/FirewallID' - name: list in: path required: true description: '`shared` or a room code.' schema: type: string minLength: 1 maxLength: 64 put: operationId: setAllowedSites summary: Replace the domains of an allowed-sites list description: | `domains` is the full desired set of Matrix-managed domains (canonicalized: lower-case, sorted, duplicates removed; at most 200). Records the change (`change`, kind `sites`) and sends a `matrix.sites.set` job. The shared list: tenant admins only; a per-room list: tenant admins and teachers the room is granted to. Errors: 403 forbidden / group_read_only (Matrix may not change the group on the FortiGate); 409 busy, conflict (the list changed since `list_version`), snapshot_stale, connector_offline, connector_outdated (the connector does not support allowed sites yet), writes_disabled (allowed-sites editing is off for the firewall), sites_not_set_up, unknown_room; 404 unknown_room for a teacher when the room is not granted to them; 422 invalid_domain; 429 rate_limited. Refused attempts are recorded too. tags: - sites requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SetAllowedSitesRequest' responses: '202': description: Sent. content: application/json: schema: $ref: '#/components/schemas/AllowedSitesChange' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/room-grants: parameters: - $ref: '#/components/parameters/TenantID' get: operationId: listRoomGrants summary: Which teachers may switch which rooms (non-admins see their own) tags: - grants parameters: - name: user_id in: query schema: type: string format: uuid responses: '200': description: Grants. content: application/json: schema: $ref: '#/components/schemas/RoomGrantList' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/users/{userID}/room-grants: parameters: - $ref: '#/components/parameters/TenantID' - $ref: '#/components/parameters/UserID' put: operationId: setRoomGrants summary: Replace a teacher's rooms on one firewall description: | Recorded as a `grants` change. Rooms to add must be known rooms of the firewall; removing is always possible. 422 not_teacher when the user is not a teacher of the tenant. tags: - grants requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SetRoomGrantsRequest' responses: '200': description: The user's grants on that firewall now. content: application/json: schema: $ref: '#/components/schemas/RoomGrantList' default: $ref: '#/components/responses/Problem' /tenants/{tenantID}/history: parameters: - $ref: '#/components/parameters/TenantID' get: operationId: listHistory summary: The change history, newest first (cursor pagination) description: | Teachers get only the changes of the rooms granted to them (including their own refused attempts on those rooms); changes without a room (firewall, grant, shared-list changes) are left out. tags: - history parameters: - name: from in: query schema: type: string format: date-time - name: to in: query schema: type: string format: date-time - name: user_id in: query schema: type: string format: uuid - name: room in: query description: Part of a room code (case-insensitive). schema: type: string maxLength: 64 - name: kind in: query schema: $ref: '#/components/schemas/ChangeKind' - name: firewall_id in: query schema: type: string format: uuid - name: cursor in: query description: next_cursor of the previous page. schema: type: string maxLength: 200 - name: limit in: query schema: type: integer minimum: 1 maximum: 200 default: 50 responses: '200': description: A page of changes. content: application/json: schema: $ref: '#/components/schemas/HistoryPage' default: $ref: '#/components/responses/Problem' components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT parameters: TenantID: name: tenantID in: path required: true schema: type: string format: uuid SiteID: name: siteID in: path required: true schema: type: string format: uuid TokenID: name: tokenID in: path required: true schema: type: string format: uuid JobID: name: jobID in: path required: true schema: type: string format: uuid ConnectorID: name: connectorID in: path required: true schema: type: string format: uuid FirewallID: name: firewallID in: path required: true schema: type: string format: uuid RoomCode: name: room in: path required: true schema: type: string minLength: 1 maxLength: 64 BulkID: name: bulkID in: path required: true schema: type: string format: uuid ScheduleID: name: scheduleID in: path required: true schema: type: string format: uuid OperationID: name: operationID in: path required: true schema: type: string format: uuid UserID: name: userID in: path required: true schema: type: string format: uuid Page: name: page in: query schema: type: integer minimum: 1 maximum: 100000 default: 1 PageSize: name: page_size in: query schema: type: integer minimum: 1 maximum: 200 default: 50 Query: name: q in: query schema: type: string maxLength: 200 AuditActor: name: actor_user_id in: query schema: type: string format: uuid AuditAction: name: action in: query schema: type: string maxLength: 100 AuditResourceType: name: resource_type in: query schema: type: string maxLength: 100 AuditFrom: name: from in: query schema: type: string format: date-time AuditTo: name: to in: query schema: type: string format: date-time responses: Problem: description: Error (RFC 7807). content: application/problem+json: schema: $ref: '#/components/schemas/Problem' schemas: Health: type: object required: - status properties: status: type: string enum: - ok Problem: type: object description: RFC 7807 problem details. required: - type - title - status properties: type: type: string description: URI reference identifying the problem type. example: about:blank title: type: string status: type: integer detail: type: string code: type: string description: Stable machine-readable error code, e.g. connector_offline. instance: type: string request_id: type: string fields: type: object description: Per-field validation errors. additionalProperties: type: string Role: type: string enum: - global_admin - tenant_admin - teacher - viewer TenantRole: type: string enum: - tenant_admin - teacher - viewer UserStatus: type: string enum: - active - disabled - deleted TenantStatus: type: string enum: - active - suspended User: type: object required: - id - email - display_name - role - tenant_id - status - created_at properties: id: type: string format: uuid email: type: string display_name: type: string role: $ref: '#/components/schemas/Role' tenant_id: type: string format: uuid nullable: true status: $ref: '#/components/schemas/UserStatus' created_at: type: string format: date-time Me: type: object description: >- The signed-in user. A user can belong to several tenants, with one role in each; global admins have every permission in every tenant. required: - id - email - display_name - status - is_global_admin - memberships - created_at properties: id: type: string format: uuid email: type: string display_name: type: string status: $ref: '#/components/schemas/UserStatus' is_global_admin: type: boolean memberships: type: array items: $ref: '#/components/schemas/TenantMembership' created_at: type: string format: date-time TenantMembership: type: object required: - tenant_id - tenant_name - tenant_status - role properties: tenant_id: type: string format: uuid tenant_name: type: string tenant_status: $ref: '#/components/schemas/TenantStatus' role: $ref: '#/components/schemas/TenantRole' UserDirectory: type: object required: - users properties: users: type: array items: $ref: '#/components/schemas/User' Tenant: type: object required: - id - name - slug - status - settings - created_at - updated_at properties: id: type: string format: uuid name: type: string slug: type: string status: $ref: '#/components/schemas/TenantStatus' settings: $ref: '#/components/schemas/TenantSettings' created_at: type: string format: date-time updated_at: type: string format: date-time TenantRetention: type: object additionalProperties: false description: Overrides of the server's retention windows (sent as a whole). properties: job_days: type: integer minimum: 7 maximum: 730 description: Finished connector jobs. audit_days: type: integer minimum: 30 maximum: 3650 description: Audit log entries. TenantSettings: type: object additionalProperties: false properties: default_timezone: type: string maxLength: 64 description: >- IANA time zone of schedules shown for firewalls without a site (default UTC). retention: $ref: '#/components/schemas/TenantRetention' TenantList: type: object required: - items - page - page_size - total properties: items: type: array items: $ref: '#/components/schemas/Tenant' page: type: integer page_size: type: integer total: type: integer UpdateTenantRequest: type: object additionalProperties: false properties: settings: $ref: '#/components/schemas/TenantSettings' AdminOverview: type: object required: - tenants_total - tenants_active - global_admins - tenant_users - firewalls_total - firewalls_online - rooms_total - rooms_disabled - connectors_total - connectors_online - tenants properties: tenants_total: type: integer tenants_active: type: integer global_admins: type: integer tenant_users: type: integer firewalls_total: type: integer firewalls_online: type: integer description: Enabled and reporting online. rooms_total: type: integer rooms_disabled: type: integer description: Rooms whose internet access is off. connectors_total: type: integer description: Not revoked. connectors_online: type: integer tenants: type: array items: $ref: '#/components/schemas/TenantMatrixCounts' TenantMatrixCounts: type: object required: - tenant_id - name - status - firewalls_total - firewalls_online - rooms_total - connectors_total - connectors_online properties: tenant_id: type: string format: uuid name: type: string status: type: string firewalls_total: type: integer firewalls_online: type: integer rooms_total: type: integer connectors_total: type: integer connectors_online: type: integer AdminConnectorReleaseList: type: object required: - items - adoption - update_channel - releases_enabled properties: items: type: array items: $ref: '#/components/schemas/AdminConnectorRelease' adoption: type: array items: $ref: '#/components/schemas/ConnectorVersionCount' update_channel: type: string enum: - stable - dev releases_enabled: type: boolean description: MATRIX_RELEASE_SIGNING_KEY is set. public_key: type: string description: Base64 Ed25519 key connectors verify releases with. AdminConnectorRelease: type: object required: - id - version - channel - sha256 - size_bytes - created_at - current - file_name - download_url - download_expires_at properties: id: type: string format: uuid version: type: string channel: type: string enum: - stable - dev sha256: type: string size_bytes: type: integer format: int64 notes: type: string created_at: type: string format: date-time current: type: boolean description: The release connectors are updated to. file_name: type: string download_url: type: string description: The installer (no sign-in needed until it expires). download_expires_at: type: string format: date-time ConnectorVersionCount: type: object required: - version - count properties: version: type: string description: Empty when the connector has not reported one. count: type: integer Site: type: object required: - id - tenant_id - name - description - timezone - created_at - updated_at properties: id: type: string format: uuid tenant_id: type: string format: uuid name: type: string description: type: string timezone: type: string description: IANA time zone e.g. Europe/Sofia.: null created_at: type: string format: date-time updated_at: type: string format: date-time SiteList: type: object required: - items properties: items: type: array items: $ref: '#/components/schemas/Site' CreateSiteRequest: type: object required: - name additionalProperties: false properties: name: type: string minLength: 1 maxLength: 200 description: type: string maxLength: 2000 timezone: type: string minLength: 1 maxLength: 64 UpdateSiteRequest: type: object additionalProperties: false properties: name: type: string minLength: 1 maxLength: 200 description: type: string maxLength: 2000 timezone: type: string minLength: 1 maxLength: 64 AuditEntry: type: object required: - id - ts - tenant_id - actor_user_id - actor_email - action - resource_type - resource_id - before - after - ip - request_id properties: id: type: string format: uuid ts: type: string format: date-time tenant_id: type: string format: uuid nullable: true actor_user_id: type: string format: uuid nullable: true actor_email: type: string action: type: string resource_type: type: string resource_id: type: string before: type: object nullable: true additionalProperties: true after: type: object nullable: true additionalProperties: true ip: type: string request_id: type: string AuditList: type: object required: - items - page - page_size - total properties: items: type: array items: $ref: '#/components/schemas/AuditEntry' page: type: integer page_size: type: integer total: type: integer TenantDashboard: type: object required: - connectors_total - connectors_online - firewalls_total - firewalls_online - rooms_total - rooms_disabled - schedules_open - sites_total - changes_today - changes_failed_today properties: connectors_total: type: integer connectors_online: type: integer firewalls_total: type: integer firewalls_online: type: integer rooms_total: type: integer rooms_disabled: type: integer description: Rooms whose internet access is off. schedules_open: type: integer description: Pending or firing re-enable schedules. sites_total: type: integer changes_today: type: integer description: Changes in the last 24 hours (without grant changes). changes_failed_today: type: integer description: Of those unconfirmed or failed.: null EnrollmentTokenStatus: type: string enum: - active - revoked - expired - exhausted EnrollmentToken: type: object required: - id - tenant_id - site_id - label - max_uses - uses - expires_at - revoked_at - created_by - created_by_email - created_at - status properties: id: type: string format: uuid tenant_id: type: string format: uuid site_id: type: string format: uuid nullable: true label: type: string max_uses: type: integer nullable: true uses: type: integer expires_at: type: string format: date-time nullable: true revoked_at: type: string format: date-time nullable: true created_by: type: string format: uuid nullable: true created_by_email: type: string created_at: type: string format: date-time status: $ref: '#/components/schemas/EnrollmentTokenStatus' EnrollmentTokenList: type: object required: - items properties: items: type: array items: $ref: '#/components/schemas/EnrollmentToken' CreateEnrollmentTokenRequest: type: object additionalProperties: false properties: label: type: string maxLength: 200 site_id: type: string format: uuid expires_at: type: string format: date-time max_uses: type: integer minimum: 1 maximum: 100000 CreatedEnrollmentToken: type: object required: - token - secret - install_command - cli_command - download_url properties: token: $ref: '#/components/schemas/EnrollmentToken' secret: type: string description: The raw token. Shown only once. install_command: type: string description: msiexec one-liner for a silent installation. cli_command: type: string description: Enrolls an installed connector from the command line. download_url: type: string description: Where the connector installer can be downloaded (may be empty). ConnectorRelease: type: object required: - version - channel - sha256 - size_bytes - created_at - download_url - download_expires_at properties: version: type: string example: 0.1.0 channel: type: string enum: - stable - dev sha256: type: string size_bytes: type: integer format: int64 notes: type: string created_at: type: string format: date-time download_url: type: string description: The installer (no sign-in needed until it expires). download_expires_at: type: string format: date-time DeleteEnrollmentTokenRequest: type: object required: - step_up_token additionalProperties: false properties: step_up_token: type: string minLength: 1 maxLength: 4096 Connector: type: object required: - id - site_id - name - hostname - domain - version - capabilities - status - last_seen_at - firewall_count - created_at properties: id: type: string format: uuid site_id: type: string format: uuid nullable: true name: type: string hostname: type: string domain: type: string version: type: string capabilities: type: array items: type: string status: type: string enum: - online - offline last_seen_at: type: string format: date-time nullable: true firewall_count: type: integer created_at: type: string format: date-time ConnectorList: type: object required: - items properties: items: type: array items: $ref: '#/components/schemas/Connector' UpdateConnectorRequest: type: object additionalProperties: false properties: name: type: string maxLength: 200 site_id: type: string format: uuid clear_site: type: boolean description: Remove the connector from its site. JobStatus: type: string enum: - created - sent - acked - running - succeeded - failed - timeout - cancelled Job: type: object required: - id - connector_id - firewall_id - policy_id - room_code - operation_id - type - status - created_by - created_at - sent_at - finished_at - progress_pct - progress_message - error_code - error - result properties: id: type: string format: uuid connector_id: type: string format: uuid firewall_id: type: string format: uuid nullable: true policy_id: type: integer format: int64 nullable: true room_code: type: string nullable: true operation_id: type: string format: uuid nullable: true type: type: string status: $ref: '#/components/schemas/JobStatus' created_by: type: string format: uuid nullable: true created_at: type: string format: date-time sent_at: type: string format: date-time nullable: true finished_at: type: string format: date-time nullable: true progress_pct: type: integer nullable: true progress_message: type: string error_code: type: string error: type: string result: type: object nullable: true additionalProperties: true description: >- The job's result payload (a CheckResult, a PolicySetResult, an AddressOpResult, a SitesSetResult), when it succeeded. JobList: type: object required: - items properties: items: type: array items: $ref: '#/components/schemas/Job' FirewallDriver: type: string enum: - fortigate - simulator description: >- simulator is an in-memory FortiGate built into the connector, for trials and tests. FirewallStatus: type: string enum: - pending - online - unreachable - auth_failed - version_mismatch - direction_invalid - error description: What the connector last reported (pending until the first report). PolicyStatus: type: string enum: - enable - disable Firewall: type: object required: - id - tenant_id - site_id - connector_id - name - driver - host - port - vdom - src_intf - dst_intf - policy_pattern - building_labels - hostname_suffix - marker_prefix - verify_tls - ca_pem - expected_version - report_interval_s - writes_enabled - address_writes_enabled - site_writes_enabled - sites_supported - enabled - has_token - credentials_version - status - status_error - error_code - fortios_version - guard_state - last_report_at - stale - created_at - updated_at properties: id: type: string format: uuid tenant_id: type: string format: uuid site_id: type: string format: uuid nullable: true connector_id: type: string format: uuid name: type: string driver: $ref: '#/components/schemas/FirewallDriver' host: type: string port: type: integer vdom: type: string src_intf: type: string description: Source interface/zone of room policies. dst_intf: type: string description: Destination interface/zone of room policies. policy_pattern: type: string description: >- RE2 matched against the whole policy name; needs (?P…), optional (?P…). building_labels: type: object additionalProperties: type: string description: Display names of buildings (building code → label). hostname_suffix: type: string example: .coding.local marker_prefix: type: string verify_tls: type: boolean ca_pem: type: string expected_version: type: string description: Pinned FortiOS version (7.4.11); empty for any. report_interval_s: type: integer writes_enabled: type: boolean address_writes_enabled: type: boolean site_writes_enabled: type: boolean description: Allowed-sites lists may be changed. sites_supported: type: boolean description: >- The firewall's connector supports allowed sites (capability "sites"). enabled: type: boolean has_token: type: boolean credentials_version: type: integer format: int64 status: $ref: '#/components/schemas/FirewallStatus' status_error: type: string error_code: type: string fortios_version: type: string guard_state: type: string description: >- accepted, pending or mismatch (the connector's local guard); empty until reported. last_report_at: type: string format: date-time nullable: true stale: type: boolean description: Rooms are out of date (no recent report connector offline or firewall not online).: null created_at: type: string format: date-time updated_at: type: string format: date-time FirewallList: type: object required: - items properties: items: type: array items: $ref: '#/components/schemas/Firewall' CreateFirewallRequest: type: object additionalProperties: false required: - name - connector_id - driver - host - src_intf - dst_intf - policy_pattern - hostname_suffix properties: name: type: string minLength: 1 maxLength: 200 connector_id: type: string format: uuid site_id: type: string format: uuid driver: $ref: '#/components/schemas/FirewallDriver' host: type: string minLength: 1 maxLength: 253 port: type: integer minimum: 1 maximum: 65535 default: 443 vdom: type: string minLength: 1 maxLength: 79 default: root src_intf: type: string minLength: 1 maxLength: 79 dst_intf: type: string minLength: 1 maxLength: 79 policy_pattern: type: string minLength: 1 maxLength: 500 building_labels: type: object maxProperties: 200 additionalProperties: type: string maxLength: 200 hostname_suffix: type: string minLength: 2 maxLength: 200 marker_prefix: type: string minLength: 1 maxLength: 64 verify_tls: type: boolean default: true ca_pem: type: string maxLength: 65536 expected_version: type: string maxLength: 20 report_interval_s: type: integer minimum: 15 maximum: 300 default: 30 writes_enabled: type: boolean default: false address_writes_enabled: type: boolean default: false site_writes_enabled: type: boolean default: false enabled: type: boolean default: true token: type: string minLength: 1 maxLength: 512 writeOnly: true UpdateFirewallRequest: type: object additionalProperties: false properties: name: type: string minLength: 1 maxLength: 200 connector_id: type: string format: uuid site_id: type: string format: uuid clear_site: type: boolean driver: $ref: '#/components/schemas/FirewallDriver' host: type: string minLength: 1 maxLength: 253 port: type: integer minimum: 1 maximum: 65535 vdom: type: string minLength: 1 maxLength: 79 src_intf: type: string minLength: 1 maxLength: 79 dst_intf: type: string minLength: 1 maxLength: 79 policy_pattern: type: string minLength: 1 maxLength: 500 building_labels: type: object maxProperties: 200 additionalProperties: type: string maxLength: 200 hostname_suffix: type: string minLength: 2 maxLength: 200 marker_prefix: type: string minLength: 1 maxLength: 64 verify_tls: type: boolean ca_pem: type: string maxLength: 65536 expected_version: type: string maxLength: 20 report_interval_s: type: integer minimum: 15 maximum: 300 writes_enabled: type: boolean address_writes_enabled: type: boolean site_writes_enabled: type: boolean enabled: type: boolean FirewallToken: type: object additionalProperties: false required: - token properties: token: type: string minLength: 1 maxLength: 512 writeOnly: true RefreshRequest: type: object additionalProperties: false required: - scope properties: scope: type: string enum: - rooms - addresses - all RoomsView: type: object required: - firewalls - rooms properties: firewalls: type: array items: $ref: '#/components/schemas/RoomFirewall' rooms: type: array items: $ref: '#/components/schemas/Room' RoomFirewall: type: object required: - id - name - stale - updated_at - error - error_code - simulated - guard_state - writes_enabled - address_writes_enabled - site_writes_enabled - sites_supported - shared_allowed_sites - status - connector_online - enabled properties: id: type: string format: uuid name: type: string stale: type: boolean updated_at: type: string format: date-time nullable: true description: When the rooms were last read. error: type: string error_code: type: string simulated: type: boolean guard_state: type: string writes_enabled: type: boolean address_writes_enabled: type: boolean site_writes_enabled: type: boolean sites_supported: type: boolean shared_allowed_sites: type: integer description: Domains in the firewall's shared allowed-sites list. status: $ref: '#/components/schemas/FirewallStatus' connector_online: type: boolean enabled: type: boolean Room: type: object required: - firewall_id - code - building - building_label - policy_id - policy_name - status - present - can_manage - busy_job_id - schedule - last_change - allowed_sites properties: firewall_id: type: string format: uuid code: type: string example: SB1-102 building: type: string building_label: type: string policy_id: type: integer format: int64 policy_name: type: string status: $ref: '#/components/schemas/PolicyStatus' present: type: boolean description: False when the last report no longer contained the room. can_manage: type: boolean description: The caller may switch this room. busy_job_id: type: string format: uuid nullable: true allowed_sites: type: integer description: Domains in the room's own allowed-sites list (0 when it has none). schedule: allOf: - $ref: '#/components/schemas/RoomSchedule' nullable: true last_change: allOf: - $ref: '#/components/schemas/LastChange' nullable: true RoomSchedule: type: object required: - id - reenable_at properties: id: type: string format: uuid reenable_at: type: string format: date-time LastChange: type: object required: - result - at properties: result: $ref: '#/components/schemas/ChangeResult' at: type: string format: date-time SetRoomStatusRequest: type: object additionalProperties: false required: - status properties: status: $ref: '#/components/schemas/PolicyStatus' reenable_at: type: string format: date-time description: 'Disable only: switch on again then (5 minutes to 7 days ahead).' RoomStatusChange: type: object required: - change - job properties: change: $ref: '#/components/schemas/ChangeEvent' job: $ref: '#/components/schemas/Job' BulkStatusRequest: type: object additionalProperties: false required: - status properties: status: $ref: '#/components/schemas/PolicyStatus' rooms: type: array minItems: 1 maxItems: 2000 items: type: string minLength: 1 maxLength: 64 building: type: string minLength: 1 maxLength: 64 description: Every present room of the building (when rooms is not given). reenable_at: type: string format: date-time BulkStatusResult: type: object required: - bulk properties: bulk: $ref: '#/components/schemas/BulkAction' BulkAction: type: object required: - id - firewall_id - desired - building - rooms - reenable_at - created_by - created_at - items properties: id: type: string format: uuid firewall_id: type: string format: uuid desired: $ref: '#/components/schemas/PolicyStatus' building: type: string rooms: type: array items: type: string reenable_at: type: string format: date-time nullable: true created_by: type: string format: uuid nullable: true created_at: type: string format: date-time items: type: array items: $ref: '#/components/schemas/BulkItem' BulkItem: type: object required: - room - change_id - job_id - result properties: room: type: string change_id: type: string format: uuid nullable: true job_id: type: string format: uuid nullable: true result: $ref: '#/components/schemas/ChangeResult' error: type: string description: Why the room was not sent (busy). ScheduleStatus: type: string enum: - pending - firing - done - cancelled - failed Schedule: type: object required: - id - firewall_id - room_code - policy_id - reenable_at - status - created_by - created_by_email - disable_job_id - enable_job_id - bulk_id - detail - created_at - updated_at properties: id: type: string format: uuid firewall_id: type: string format: uuid room_code: type: string policy_id: type: integer format: int64 reenable_at: type: string format: date-time status: $ref: '#/components/schemas/ScheduleStatus' created_by: type: string format: uuid nullable: true created_by_email: type: string disable_job_id: type: string format: uuid nullable: true enable_job_id: type: string format: uuid nullable: true bulk_id: type: string format: uuid nullable: true detail: type: string created_at: type: string format: date-time updated_at: type: string format: date-time ScheduleList: type: object required: - items properties: items: type: array items: $ref: '#/components/schemas/Schedule' AddressGroupSummary: type: object required: - policy_id - name - room - building - count - version - editable - reason properties: policy_id: type: integer format: int64 name: type: string room: type: string building: type: string count: type: integer version: type: string description: Pass as group_version when changing the group. editable: type: boolean reason: type: string description: Why the group is read-only (English). AddressMember: type: object required: - name - ip - type - editable - reason properties: name: type: string ip: type: string description: Empty for objects that are not a /32. type: type: string editable: type: boolean reason: type: string AddressGroup: allOf: - $ref: '#/components/schemas/AddressGroupSummary' - type: object required: - members properties: members: type: array items: $ref: '#/components/schemas/AddressMember' AddressGroupsView: type: object required: - groups - stale - updated_at - error properties: groups: type: array items: $ref: '#/components/schemas/AddressGroupSummary' stale: type: boolean updated_at: type: string format: date-time nullable: true error: type: string AddressGroupDetail: type: object required: - group - operations - stale - updated_at properties: group: $ref: '#/components/schemas/AddressGroup' operations: type: array items: $ref: '#/components/schemas/AddressOperation' description: The caller's interrupted operations on this group (retry them). stale: type: boolean updated_at: type: string format: date-time nullable: true AddressUpdateRequest: type: object additionalProperties: false required: - policy_id - group - name - ip - expected_ip - group_version - request_id properties: policy_id: type: integer format: int64 minimum: 1 maximum: 4294967295 group: type: string minLength: 1 maxLength: 255 name: type: string minLength: 1 maxLength: 255 ip: type: string maxLength: 15 expected_ip: type: string maxLength: 15 group_version: type: string pattern: ^[0-9a-f]{64}$ request_id: type: string format: uuid AddressCreateRequest: type: object additionalProperties: false required: - policy_id - group - name - ip - group_version - request_id properties: policy_id: type: integer format: int64 minimum: 1 maximum: 4294967295 group: type: string minLength: 1 maxLength: 255 name: type: string minLength: 1 maxLength: 255 ip: type: string maxLength: 15 group_version: type: string pattern: ^[0-9a-f]{64}$ request_id: type: string format: uuid RetryAddressOperationRequest: type: object additionalProperties: false required: - group_version properties: group_version: type: string pattern: ^[0-9a-f]{64}$ AddressStage: type: string enum: - prepared - update_sent - create_sent - created - member_sent - done AddressOperation: type: object required: - id - firewall_id - actor_id - kind - policy_id - room - group_name - object_name - desired_ip - previous_ip - group_version - stage - address_uuid - result - last_job_id - retryable - created_at - updated_at properties: id: type: string format: uuid firewall_id: type: string format: uuid actor_id: type: string format: uuid kind: type: string enum: - update - create policy_id: type: integer format: int64 room: type: string group_name: type: string object_name: type: string desired_ip: type: string previous_ip: type: string group_version: type: string stage: $ref: '#/components/schemas/AddressStage' address_uuid: type: string result: $ref: '#/components/schemas/ChangeResult' last_job_id: type: string format: uuid nullable: true retryable: type: boolean description: Interrupted after a write started (only its author may retry). created_at: type: string format: date-time updated_at: type: string format: date-time AddressOperationStarted: type: object required: - operation - job - change properties: operation: $ref: '#/components/schemas/AddressOperation' job: $ref: '#/components/schemas/Job' change: $ref: '#/components/schemas/ChangeEvent' SiteEntry: type: object required: - domain - object - owned - editable - reason properties: domain: type: string description: >- FQDN of an fqdn address object (may start with "*."); empty for other objects. object: type: string description: The address object on the FortiGate. owned: type: boolean description: Created by Matrix. editable: type: boolean description: Matrix may remove it from the list (objects Matrix created). reason: type: string description: Why the entry is read-only (English). SitesPolicy: type: object required: - policy_id - name - status - covers properties: policy_id: type: integer format: int64 name: type: string status: $ref: '#/components/schemas/PolicyStatus' covers: type: boolean description: >- Its srcaddr includes the room address group(s) (every room's for the shared list). SitesSetup: type: string enum: - ok - group_missing - policy_missing - policy_disabled - policy_not_covering - unknown description: | ok: group and an enabled ACCEPT policy covering the room(s) exist; unknown: not reported yet (the connector does not support allowed sites, or has not reported them). AllowedSitesList: type: object required: - list - room - building - group - exists - policy - setup - version - editable - reason - domains - can_edit - busy_job_id - last_change properties: list: type: string description: '`shared` or the room code.' room: type: string description: Empty for the shared list. building: type: string group: type: string description: The address group on the FortiGate. exists: type: boolean policy: allOf: - $ref: '#/components/schemas/SitesPolicy' nullable: true setup: $ref: '#/components/schemas/SitesSetup' version: type: string description: >- Pass as list_version when changing the list (empty while it does not exist). editable: type: boolean description: Matrix may change the group's members. reason: type: string description: Why the group is read-only (English). domains: type: array items: $ref: '#/components/schemas/SiteEntry' can_edit: type: boolean description: The caller may change this list (role and room grants). busy_job_id: type: string format: uuid nullable: true last_change: allOf: - $ref: '#/components/schemas/LastChange' nullable: true AllowedSitesFirewall: type: object required: - id - name - stale - updated_at - error - status - connector_online - enabled - guard_state - site_writes_enabled - sites_supported properties: id: type: string format: uuid name: type: string stale: type: boolean updated_at: type: string format: date-time nullable: true description: When the lists were last read. error: type: string status: $ref: '#/components/schemas/FirewallStatus' connector_online: type: boolean enabled: type: boolean guard_state: type: string site_writes_enabled: type: boolean sites_supported: type: boolean AllowedSitesView: type: object required: - firewall - shared - rooms - can_setup properties: firewall: $ref: '#/components/schemas/AllowedSitesFirewall' shared: $ref: '#/components/schemas/AllowedSitesList' rooms: type: array items: $ref: '#/components/schemas/AllowedSitesList' can_setup: type: boolean description: The caller may view the FortiGate setup CLI (tenant admins). SetAllowedSitesRequest: type: object additionalProperties: false required: - domains - list_version properties: domains: type: array maxItems: 200 items: type: string minLength: 1 maxLength: 253 list_version: type: string pattern: ^[0-9a-f]{64}$ AllowedSitesChange: type: object required: - change - job properties: change: $ref: '#/components/schemas/ChangeEvent' job: $ref: '#/components/schemas/Job' AllowedSitesSetupCLI: type: object required: - cli - lists - warnings properties: cli: type: string description: FortiOS CLI (empty when nothing is missing). lists: type: array items: type: string description: 'What the CLI sets up: shared and room codes.' warnings: type: array items: type: string description: >- Problems the CLI cannot fix (English), e.g. a room without known address groups. RoomGrant: type: object required: - user_id - user_email - firewall_id - room_code - granted_by - created_at properties: user_id: type: string format: uuid user_email: type: string firewall_id: type: string format: uuid room_code: type: string granted_by: type: string format: uuid nullable: true created_at: type: string format: date-time RoomGrantList: type: object required: - items properties: items: type: array items: $ref: '#/components/schemas/RoomGrant' SetRoomGrantsRequest: type: object additionalProperties: false required: - firewall_id - rooms properties: firewall_id: type: string format: uuid rooms: type: array maxItems: 2000 items: type: string minLength: 1 maxLength: 64 ChangeKind: type: string description: | What a change did. `services` is read-only history: the removed Entrosity services group (no new changes of this kind are made). enum: - policy - address_update - address_create - grants - schedule - bulk - sites - services ChangeResult: type: string enum: - pending - success - unconfirmed - denied - error - cancelled ChangeEvent: type: object required: - id - firewall_id - kind - actor_id - actor_email - ip - room - policy_id - policy_name - previous - desired - result - detail - object_name - group_name - operation_id - job_id - bulk_id - schedule_id - source - metadata - created_at properties: id: type: string format: uuid firewall_id: type: string format: uuid nullable: true kind: $ref: '#/components/schemas/ChangeKind' actor_id: type: string format: uuid nullable: true description: Null for scheduled (system) changes. actor_email: type: string ip: type: string room: type: string policy_id: type: integer format: int64 nullable: true policy_name: type: string previous: type: string desired: type: string result: $ref: '#/components/schemas/ChangeResult' detail: type: string description: >- Error code or short English text; refusals carry the problem code (unknown_room, busy, …). object_name: type: string group_name: type: string operation_id: type: string format: uuid nullable: true job_id: type: string format: uuid nullable: true bulk_id: type: string format: uuid nullable: true schedule_id: type: string format: uuid nullable: true source: type: string description: matrix, or stop-internet for imported history. metadata: type: object additionalProperties: true description: >- Steps (authorization checks, journaled write stages), grant lists and error codes. created_at: type: string format: date-time HistoryPage: type: object required: - items - next_cursor properties: items: type: array items: $ref: '#/components/schemas/ChangeEvent' next_cursor: type: string nullable: true